This is an automated email from the ASF dual-hosted git repository. lgoldstein pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/mina-sshd.git
The following commit(s) were added to refs/heads/master by this push: new d567b95 [SSHD-967] Fixed extra bytes written at end of SftpRemotePathChannel#transferTo d567b95 is described below commit d567b9549b52f00266fa2d8d6d32544f6c253afa Author: Lyor Goldstein <lgoldst...@apache.org> AuthorDate: Fri Feb 21 14:00:14 2020 +0200 [SSHD-967] Fixed extra bytes written at end of SftpRemotePathChannel#transferTo --- CHANGES.md | 2 + .../subsystem/sftp/SftpRemotePathChannel.java | 283 +++++++++++++++------ .../subsystem/sftp/SftpRemotePathChannelTest.java | 183 +++++++++++++ .../sshd/client/subsystem/sftp/SftpTest.java | 150 ++++++----- 4 files changed, 464 insertions(+), 154 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index dd584ff..1a08198 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -13,3 +13,5 @@ ## Behavioral changes and enhancements * [SSHD-964](https://issues.apache.org/jira/browse/SSHD-964) - Send SSH_MSG_CHANNEL_EOF when tunnel channel being closed. + +* [SSHD-967](https://issues.apache.org/jira/browse/SSHD-967) - Extra bytes written when `SftpRemotePathChannel#transferTo` is used. \ No newline at end of file diff --git a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannel.java b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannel.java index fc81e17..52e3149 100644 --- a/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannel.java +++ b/sshd-sftp/src/main/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannel.java @@ -20,6 +20,7 @@ package org.apache.sshd.client.subsystem.sftp; import java.io.IOException; +import java.io.StreamCorruptedException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.AsynchronousCloseException; @@ -33,24 +34,29 @@ 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 java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.client.subsystem.sftp.SftpClient.Attributes; import org.apache.sshd.common.subsystem.sftp.SftpConstants; import org.apache.sshd.common.subsystem.sftp.SftpException; import org.apache.sshd.common.util.GenericUtils; import org.apache.sshd.common.util.ValidateUtils; import org.apache.sshd.common.util.io.IoUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> */ public class SftpRemotePathChannel extends FileChannel { + /** Internal allocate buffer size when copying data to/from the channel */ public static final String COPY_BUFSIZE_PROP = "sftp-channel-copy-buf-size"; + /** Default value for {@value #COPY_BUFSIZE_PROP} setting */ public static final int DEFAULT_TRANSFER_BUFFER_SIZE = IoUtils.DEFAULT_COPY_SIZE; public static final Set<SftpClient.OpenMode> READ_MODES = @@ -64,16 +70,21 @@ public class SftpRemotePathChannel extends FileChannel { SftpClient.OpenMode.Create, SftpClient.OpenMode.Truncate)); + protected final Logger log; + protected final Collection<SftpClient.OpenMode> modes; + protected final boolean closeOnExit; + protected final SftpClient sftp; + protected final SftpClient.CloseableHandle handle; + protected final Object lock = new Object(); + protected final AtomicLong posTracker = new AtomicLong(0L); + protected final AtomicReference<Thread> blockingThreadHolder = new AtomicReference<>(null); + private final String path; - private final Collection<SftpClient.OpenMode> modes; - private final boolean closeOnExit; - private final SftpClient sftp; - private final SftpClient.CloseableHandle handle; - private final Object lock = new Object(); - private final AtomicLong posTracker = new AtomicLong(0L); - private final AtomicReference<Thread> blockingThreadHolder = new AtomicReference<>(null); - - public SftpRemotePathChannel(String path, SftpClient sftp, boolean closeOnExit, Collection<SftpClient.OpenMode> modes) throws IOException { + + public SftpRemotePathChannel( + String path, SftpClient sftp, boolean closeOnExit, Collection<SftpClient.OpenMode> modes) + throws IOException { + this.log = LoggerFactory.getLogger(getClass()); this.path = ValidateUtils.checkNotNullAndNotEmpty(path, "No remote file path specified"); this.modes = Objects.requireNonNull(modes, "No channel modes specified"); this.sftp = Objects.requireNonNull(sftp, "No SFTP client instance"); @@ -87,41 +98,69 @@ public class SftpRemotePathChannel extends FileChannel { @Override public int read(ByteBuffer dst) throws IOException { - return (int) doRead(Collections.singletonList(dst), -1); + long totalRead = doRead(Collections.singletonList(dst), -1L); + if (totalRead >= Integer.MAX_VALUE) { + throw new StreamCorruptedException("Total read size exceeds integer: " + totalRead); + } + return (int) totalRead; } @Override public int read(ByteBuffer dst, long position) throws IOException { - if (position < 0) { - throw new IllegalArgumentException("read(" + getRemotePath() + ") illegal position to read from: " + position); + if (position < 0L) { + throw new IllegalArgumentException("read(" + getRemotePath() + ")" + + " illegal position to read from: " + position); } - return (int) doRead(Collections.singletonList(dst), position); + + long totalRead = doRead(Collections.singletonList(dst), position); + if (totalRead >= Integer.MAX_VALUE) { + throw new StreamCorruptedException("Total read size exceeds integer: " + totalRead); + } + return (int) totalRead; } @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); + Collection<ByteBuffer> buffers = Arrays.asList(dsts) + .subList(offset, offset + length); + return doRead(buffers, -1L); } - protected long doRead(List<ByteBuffer> buffers, long position) throws IOException { + protected long doRead(Collection<? extends ByteBuffer> buffers, long position) throws IOException { ensureOpen(READ_MODES); + + ClientSession clientSession = sftp.getClientSession(); + int copySize = clientSession.getIntProperty(COPY_BUFSIZE_PROP, DEFAULT_TRANSFER_BUFFER_SIZE); + boolean debugEnabled = log.isDebugEnabled(); + if (debugEnabled) { + log.debug("doRead({})[position={}] fill {} buffers using copySize={}", + this, position, buffers.size(), copySize); + } + + boolean completed = false; + boolean eof = false; + long totalRead = 0; + int numBufsUsed = 0; + synchronized (lock) { - boolean completed = false; - boolean eof = false; long curPos = (position >= 0L) ? position : posTracker.get(); try { - long totalRead = 0; - beginBlocking(); + beginBlocking("doRead"); + loop: for (ByteBuffer buffer : buffers) { + numBufsUsed++; + while (buffer.remaining() > 0) { ByteBuffer wrap = buffer; if (!buffer.hasArray()) { - wrap = ByteBuffer.allocate(Math.min(IoUtils.DEFAULT_COPY_SIZE, buffer.remaining())); + wrap = ByteBuffer.allocate(Math.min(copySize, buffer.remaining())); } - int read = sftp.read(handle, curPos, wrap.array(), wrap.arrayOffset() + wrap.position(), wrap.remaining()); + + int read = sftp.read(handle, curPos, wrap.array(), + wrap.arrayOffset() + wrap.position(), wrap.remaining()); if (read > 0) { + // reference equality on purpose if (wrap == buffer) { wrap.position(wrap.position() + read); } else { @@ -136,60 +175,97 @@ public class SftpRemotePathChannel extends FileChannel { } } completed = true; - if (totalRead > 0) { - return totalRead; - } - - if (eof) { - return -1; - } else { - return 0; - } } finally { if (position < 0L) { posTracker.set(curPos); } - endBlocking(completed); + endBlocking("doRead", completed); } } + + if (debugEnabled) { + log.debug("doRead({})[position={}] filled {}/{} with copySize={} - totalRead={}, completed={}, eof={}", + this, position, numBufsUsed, buffers.size(), copySize, totalRead, completed, eof); + } + + if (totalRead > 0L) { + return totalRead; + } + + if (eof) { + return -1L; + } else { + return 0L; + } } @Override public int write(ByteBuffer src) throws IOException { - return (int) doWrite(Collections.singletonList(src), -1); + long totalWritten = doWrite(Collections.singletonList(src), -1L); + if (totalWritten >= Integer.MAX_VALUE) { + throw new StreamCorruptedException("Total written size exceeds integer: " + totalWritten); + } + + return (int) totalWritten; } @Override public int write(ByteBuffer src, long position) throws IOException { if (position < 0L) { - throw new IllegalArgumentException("write(" + getRemotePath() + ") illegal position to write to: " + position); + throw new IllegalArgumentException("write(" + getRemotePath() + ")" + + " illegal position to write to: " + position); } - return (int) doWrite(Collections.singletonList(src), position); + + long totalWritten = doWrite(Collections.singletonList(src), position); + if (totalWritten >= Integer.MAX_VALUE) { + throw new StreamCorruptedException("Total written size exceeds integer: " + totalWritten); + } + + return (int) totalWritten; } @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); + Collection<ByteBuffer> buffers = Arrays.asList(srcs) + .subList(offset, offset + length); + return doWrite(buffers, -1L); } - protected long doWrite(List<ByteBuffer> buffers, long position) throws IOException { + protected long doWrite(Collection<? extends ByteBuffer> buffers, long position) throws IOException { ensureOpen(WRITE_MODES); + + ClientSession clientSession = sftp.getClientSession(); + int copySize = clientSession.getIntProperty( + COPY_BUFSIZE_PROP, DEFAULT_TRANSFER_BUFFER_SIZE); + boolean debugEnabled = log.isDebugEnabled(); + if (debugEnabled) { + log.debug("doWrite({})[position={}] write {} buffers using copySize={}", + this, position, buffers.size(), copySize); + } + + boolean completed = false; + long totalWritten = 0L; + int numBufsUsed = 0; + synchronized (lock) { - boolean completed = false; long curPos = (position >= 0L) ? position : posTracker.get(); try { - long totalWritten = 0L; - beginBlocking(); + beginBlocking("doWrite"); + for (ByteBuffer buffer : buffers) { + numBufsUsed++; + while (buffer.remaining() > 0) { ByteBuffer wrap = buffer; if (!buffer.hasArray()) { - wrap = ByteBuffer.allocate(Math.min(IoUtils.DEFAULT_COPY_SIZE, buffer.remaining())); + wrap = ByteBuffer.allocate(Math.min(copySize, 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); + sftp.write(handle, curPos, wrap.array(), + wrap.arrayOffset() + wrap.position(), written); + // reference equality on purpose if (wrap == buffer) { wrap.position(wrap.position() + written); } @@ -198,14 +274,20 @@ public class SftpRemotePathChannel extends FileChannel { } } completed = true; - return totalWritten; } finally { if (position < 0L) { posTracker.set(curPos); } - endBlocking(completed); + endBlocking("doWrite", completed); } } + + if (debugEnabled) { + log.debug("doWrite({})[position={}] used {}/{} with copySize={} - totalWritten={}, completed={}", + this, position, numBufsUsed, buffers.size(), copySize, totalWritten, completed); + } + + return totalWritten; } @Override @@ -217,7 +299,8 @@ public class SftpRemotePathChannel extends FileChannel { @Override public FileChannel position(long newPosition) throws IOException { if (newPosition < 0L) { - throw new IllegalArgumentException("position(" + getRemotePath() + ") illegal file channel position: " + newPosition); + throw new IllegalArgumentException("position(" + getRemotePath() + ")" + + " illegal file channel position: " + newPosition); } ensureOpen(Collections.emptySet()); @@ -228,7 +311,8 @@ public class SftpRemotePathChannel extends FileChannel { @Override public long size() throws IOException { ensureOpen(Collections.emptySet()); - return sftp.stat(handle).getSize(); + Attributes stat = sftp.stat(handle); + return stat.getSize(); } @Override @@ -245,24 +329,37 @@ public class SftpRemotePathChannel extends FileChannel { @Override public long transferTo(long position, long count, WritableByteChannel target) throws IOException { - if ((position < 0) || (count < 0)) { - throw new IllegalArgumentException("transferTo(" + getRemotePath() + ") illegal position (" + position + ") or count (" + count + ")"); + if ((position < 0L) || (count < 0L)) { + throw new IllegalArgumentException("transferTo(" + getRemotePath() + ")" + + " illegal position (" + position + ") or count (" + count + ")"); } ensureOpen(READ_MODES); + + ClientSession clientSession = sftp.getClientSession(); + int copySize = clientSession.getIntProperty( + COPY_BUFSIZE_PROP, DEFAULT_TRANSFER_BUFFER_SIZE); + boolean debugEnabled = log.isDebugEnabled(); + if (debugEnabled) { + log.debug("transferTo({})[position={}, count={}] use copySize={} for target={}", + this, position, count, copySize, target); + } + + boolean completed = false; + boolean eof = false; + long curPos = position; + int bufSize = (int) Math.min(count, copySize); + byte[] buffer = new byte[bufSize]; + long totalRead = 0L; + synchronized (lock) { - boolean completed = false; - boolean eof = false; - long curPos = position; try { - beginBlocking(); + beginBlocking("transferTo"); - int bufSize = (int) Math.min(count, Short.MAX_VALUE + 1); - byte[] buffer = new byte[bufSize]; - long totalRead = 0L; while (totalRead < count) { - int read = sftp.read(handle, curPos, buffer, 0, buffer.length); + int read = sftp.read(handle, curPos, buffer, 0, + (int) Math.min(count - totalRead, buffer.length)); if (read > 0) { - ByteBuffer wrap = ByteBuffer.wrap(buffer); + ByteBuffer wrap = ByteBuffer.wrap(buffer, 0, read); while (wrap.remaining() > 0) { target.write(wrap); } @@ -273,21 +370,35 @@ public class SftpRemotePathChannel extends FileChannel { } } completed = true; - return totalRead > 0 ? totalRead : eof ? -1 : 0; } finally { - endBlocking(completed); + endBlocking("transferTo", completed); } } + + if (debugEnabled) { + log.debug("transferTo({})[position={}, count={}] with copySize={} - totalRead={}, eo{} for target={}", + this, position, count, copySize, totalRead, eof, target); + } + + return totalRead > 0L ? totalRead : eof ? -1L : 0L; } @Override public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { - if ((position < 0) || (count < 0)) { - throw new IllegalArgumentException("transferFrom(" + getRemotePath() + ") illegal position (" + position + ") or count (" + count + ")"); + if ((position < 0L) || (count < 0L)) { + throw new IllegalArgumentException("transferFrom(" + getRemotePath() + ")" + + " illegal position (" + position + ") or count (" + count + ")"); } ensureOpen(WRITE_MODES); - int copySize = sftp.getClientSession().getIntProperty(COPY_BUFSIZE_PROP, DEFAULT_TRANSFER_BUFFER_SIZE); + ClientSession clientSession = sftp.getClientSession(); + int copySize = clientSession.getIntProperty(COPY_BUFSIZE_PROP, DEFAULT_TRANSFER_BUFFER_SIZE); + boolean debugEnabled = log.isDebugEnabled(); + if (debugEnabled) { + log.debug("transferFrom({})[position={}, count={}] use copySize={} for source={}", + this, position, count, copySize, src); + } + boolean completed = false; long curPos = (position >= 0L) ? position : posTracker.get(); long totalRead = 0L; @@ -295,10 +406,11 @@ public class SftpRemotePathChannel extends FileChannel { synchronized (lock) { try { - beginBlocking(); + beginBlocking("transferFrom"); while (totalRead < count) { - ByteBuffer wrap = ByteBuffer.wrap(buffer, 0, (int) Math.min(buffer.length, count - totalRead)); + 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); @@ -309,16 +421,22 @@ public class SftpRemotePathChannel extends FileChannel { } } completed = true; - return totalRead; } finally { - endBlocking(completed); + endBlocking("transferFrom", completed); } } + + if (debugEnabled) { + log.debug("transferFrom({})[position={}, count={}] use copySize={} - totalRead={}, completed={} for source={}", + this, position, count, copySize, totalRead, completed, src); + } + return totalRead; } @Override public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException { - throw new UnsupportedOperationException("map(" + getRemotePath() + ")[" + mode + "," + position + "," + size + "] N/A"); + throw new UnsupportedOperationException("map(" + getRemotePath() + ")" + + "[" + mode + "," + position + "," + size + "] N/A"); } @Override @@ -327,7 +445,7 @@ public class SftpRemotePathChannel extends FileChannel { } @Override - public FileLock tryLock(final long position, final long size, boolean shared) throws IOException { + public FileLock tryLock(long position, long size, boolean shared) throws IOException { ensureOpen(Collections.emptySet()); try { @@ -347,7 +465,6 @@ public class SftpRemotePathChannel extends FileChannel { return acquiredBy().isOpen() && valid.get(); } - @SuppressWarnings("synthetic-access") @Override public void release() throws IOException { if (valid.compareAndSet(true, false)) { @@ -359,6 +476,10 @@ public class SftpRemotePathChannel extends FileChannel { @Override protected void implCloseChannel() throws IOException { + if (log.isDebugEnabled()) { + log.debug("implCloseChannel({}) closeOnExit={}", this, closeOnExit); + } + try { Thread thread = blockingThreadHolder.get(); if (thread != null) { @@ -375,12 +496,21 @@ public class SftpRemotePathChannel extends FileChannel { } } - private void beginBlocking() { + protected void beginBlocking(Object actionHint) { + if (log.isDebugEnabled()) { + log.debug("beginBlocking({})[{}]", this, actionHint); + } + begin(); blockingThreadHolder.set(Thread.currentThread()); } - private void endBlocking(boolean completed) throws AsynchronousCloseException { + protected void endBlocking(Object actionHint, boolean completed) + throws AsynchronousCloseException { + if (log.isDebugEnabled()) { + log.debug("endBlocking({})[{}] completed={}", this, actionHint, completed); + } + blockingThreadHolder.set(null); end(completed); } @@ -390,8 +520,7 @@ public class SftpRemotePathChannel extends FileChannel { * 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 + * @throws IOException If channel not open or the required modes are not satisfied */ private void ensureOpen(Collection<SftpClient.OpenMode> reqModes) throws IOException { if (!isOpen()) { @@ -405,7 +534,9 @@ public class SftpRemotePathChannel extends FileChannel { } } - throw new IOException("ensureOpen(" + getRemotePath() + ") current channel modes (" + this.modes + ") do contain any of the required: " + reqModes); + throw new IOException("ensureOpen(" + getRemotePath() + ")" + + " current channel modes (" + this.modes + ")" + + " do contain any of the required ones: " + reqModes); } } diff --git a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannelTest.java b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannelTest.java new file mode 100644 index 0000000..2a496a9 --- /dev/null +++ b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpRemotePathChannelTest.java @@ -0,0 +1,183 @@ +/* + * 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.Writer; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.Date; +import java.util.EnumSet; +import java.util.concurrent.TimeUnit; + +import org.apache.sshd.client.session.ClientSession; +import org.apache.sshd.common.subsystem.sftp.SftpConstants; +import org.apache.sshd.util.test.CommonTestSupportUtils; +import org.junit.Before; +import org.junit.FixMethodOrder; +import org.junit.Test; +import org.junit.runners.MethodSorters; + +/** + * @author <a href="mailto:d...@mina.apache.org">Apache MINA SSHD Project</a> + */ +@FixMethodOrder(MethodSorters.NAME_ASCENDING) +@SuppressWarnings("checkstyle:MethodCount") +public class SftpRemotePathChannelTest extends AbstractSftpClientTestSupport { + public SftpRemotePathChannelTest() throws IOException { + super(); + } + + @Before + public void setUp() throws Exception { + setupServer(); + } + + @Test // see SSHD-697 + public void testFileChannel() throws IOException { + Path targetPath = detectTargetFolder(); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName()); + Path lclFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + ".txt"); + Files.deleteIfExists(lclFile); + byte[] expected = (getClass().getName() + "#" + getCurrentTestName() + "(" + new Date() + ")").getBytes(StandardCharsets.UTF_8); + + try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port) + .verify(7L, TimeUnit.SECONDS) + .getSession()) { + session.addPasswordIdentity(getCurrentTestName()); + session.auth().verify(5L, TimeUnit.SECONDS); + + try (SftpClient sftp = createSftpClient(session)) { + Path parentPath = targetPath.getParent(); + String remFilePath = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, lclFile); + + try (FileChannel fc = sftp.openRemotePathChannel( + remFilePath, EnumSet.of( + StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE))) { + int writeLen = fc.write(ByteBuffer.wrap(expected)); + assertEquals("Mismatched written length", expected.length, writeLen); + + FileChannel fcPos = fc.position(0L); + assertSame("Mismatched positioned file channel", fc, fcPos); + + byte[] actual = new byte[expected.length]; + int readLen = fc.read(ByteBuffer.wrap(actual)); + assertEquals("Mismatched read len", writeLen, readLen); + assertArrayEquals("Mismatched read data", expected, actual); + } + } + } + + byte[] actual = Files.readAllBytes(lclFile); + assertArrayEquals("Mismatched persisted data", expected, actual); + } + + @Test // see SSHD-967 + public void testTransferToFileChannel() throws IOException { + Path targetPath = detectTargetFolder(); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName()); + Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + "-src.txt"); + Path parentPath = targetPath.getParent(); + + Files.deleteIfExists(srcFile); + try (Writer output = Files.newBufferedWriter(srcFile, StandardCharsets.UTF_8)) { + String seed = getClass().getName() + "#" + getCurrentTestName() + "(" + new Date() + ")"; + for (long totalWritten = 0L; + totalWritten <= SftpRemotePathChannel.DEFAULT_TRANSFER_BUFFER_SIZE; + totalWritten += seed.length()) { + output.append(seed).append(System.lineSeparator()); + } + } + + byte[] expected = Files.readAllBytes(srcFile); + Path dstFile = srcFile.getParent().resolve(getCurrentTestName() + "-dst.txt"); + Files.deleteIfExists(dstFile); + + String remFilePath = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, srcFile); + try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port) + .verify(7L, TimeUnit.SECONDS) + .getSession()) { + session.addPasswordIdentity(getCurrentTestName()); + session.auth().verify(5L, TimeUnit.SECONDS); + + try (SftpClient sftp = createSftpClient(session); + FileChannel srcChannel = sftp.openRemotePathChannel( + remFilePath, EnumSet.of(StandardOpenOption.READ)); + FileChannel dstChannel = FileChannel.open(dstFile, + StandardOpenOption.CREATE, StandardOpenOption.WRITE)) { + long numXfered = srcChannel.transferTo(0L, expected.length, dstChannel); + assertEquals("Mismatched reported transfer count", expected.length, numXfered); + } + } + + byte[] actual = Files.readAllBytes(dstFile); + assertEquals("Mismatched transfered size", expected.length, actual.length); + assertArrayEquals("Mismatched transferred data", expected, actual); + } + + @Test // see SSHD-967 + public void testTransferFromFileChannel() throws IOException { + Path targetPath = detectTargetFolder(); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName()); + Path srcFile = assertHierarchyTargetFolderExists(lclSftp).resolve(getCurrentTestName() + "-src.txt"); + Path parentPath = targetPath.getParent(); + + Files.deleteIfExists(srcFile); + try (Writer output = Files.newBufferedWriter(srcFile, StandardCharsets.UTF_8)) { + String seed = getClass().getName() + "#" + getCurrentTestName() + "(" + new Date() + ")"; + for (long totalWritten = 0L; + totalWritten <= SftpRemotePathChannel.DEFAULT_TRANSFER_BUFFER_SIZE; + totalWritten += seed.length()) { + output.append(seed).append(System.lineSeparator()); + } + } + + byte[] expected = Files.readAllBytes(srcFile); + Path dstFile = srcFile.getParent().resolve(getCurrentTestName() + "-dst.txt"); + Files.deleteIfExists(dstFile); + + String remFilePath = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, dstFile); + try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port) + .verify(7L, TimeUnit.SECONDS) + .getSession()) { + session.addPasswordIdentity(getCurrentTestName()); + session.auth().verify(5L, TimeUnit.SECONDS); + + try (SftpClient sftp = createSftpClient(session); + FileChannel dstChannel = sftp.openRemotePathChannel( + remFilePath, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.WRITE)); + FileChannel srcChannel = FileChannel.open(srcFile, StandardOpenOption.READ)) { + long numXfered = dstChannel.transferFrom(srcChannel, 0L, expected.length); + assertEquals("Mismatched reported transfer count", expected.length, numXfered); + } + } + + byte[] actual = Files.readAllBytes(dstFile); + assertEquals("Mismatched transfered size", expected.length, actual.length); + assertArrayEquals("Mismatched transferred data", expected, actual); + } +} \ No newline at end of file diff --git a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java index 17b11cf..9abf06b 100644 --- a/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java +++ b/sshd-sftp/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java @@ -26,8 +26,6 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.net.SocketTimeoutException; -import java.nio.ByteBuffer; -import java.nio.channels.FileChannel; import java.nio.channels.SeekableByteChannel; import java.nio.charset.StandardCharsets; import java.nio.file.CopyOption; @@ -44,7 +42,6 @@ import java.nio.file.attribute.PosixFilePermission; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; -import java.util.Date; import java.util.EnumSet; import java.util.LinkedList; import java.util.List; @@ -159,7 +156,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { public void testWriteOffsetIgnoredForAppendMode() throws IOException { Path targetPath = detectTargetFolder(); Path parentPath = targetPath.getParent(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); Path testFile = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt"); Files.deleteIfExists(testFile); @@ -178,7 +176,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { try (SftpClient sftp = createSftpClient(session)) { String file = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile); - try (CloseableHandle handle = sftp.open(file, OpenMode.Create, OpenMode.Write, OpenMode.Read, OpenMode.Append)) { + try (CloseableHandle handle = sftp.open( + file, OpenMode.Create, OpenMode.Write, OpenMode.Read, OpenMode.Append)) { sftp.write(handle, 7365L, expectedRandom); byte[] actualRandom = new byte[expectedRandom.length]; int readLen = sftp.read(handle, 0L, actualRandom); @@ -195,7 +194,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { } byte[] actualBytes = Files.readAllBytes(testFile); - assertEquals("Mismatched result file size", expectedRandom.length + expectedText.length, actualBytes.length); + assertEquals("Mismatched result file size", + expectedRandom.length + expectedText.length, actualBytes.length); byte[] actualRandom = Arrays.copyOfRange(actualBytes, 0, expectedRandom.length); assertArrayEquals("Mismatched random part", expectedRandom, actualRandom); @@ -208,7 +208,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { public void testReadBufferLimit() throws Exception { Path targetPath = detectTargetFolder(); Path parentPath = targetPath.getParent(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); Path testFile = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt"); byte[] expected = new byte[1024]; @@ -228,7 +229,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { byte[] actual = new byte[expected.length]; int maxAllowed = actual.length / 4; // allow less than actual - PropertyResolverUtils.updateProperty(sshd, AbstractSftpSubsystemHelper.MAX_READDATA_PACKET_LENGTH_PROP, maxAllowed); + PropertyResolverUtils.updateProperty( + sshd, AbstractSftpSubsystemHelper.MAX_READDATA_PACKET_LENGTH_PROP, maxAllowed); try (CloseableHandle handle = sftp.open(file, OpenMode.Read)) { int readLen = sftp.read(handle, 0L, actual); assertEquals("Mismatched read len", maxAllowed, readLen); @@ -283,8 +285,9 @@ public class SftpTest extends AbstractSftpClientTestSupport { private void testCannotEscapeRoot(boolean useAbsolutePath) throws Exception { Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); - assertHierarchyTargetFolderExists(lclSftp); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + lclSftp = assertHierarchyTargetFolderExists(lclSftp); sshd.setFileSystemFactory(new VirtualFileSystemFactory(lclSftp)); try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port) @@ -351,7 +354,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { public void testNormalizeRemotePathsValues() throws Exception { Path targetPath = detectTargetFolder(); Path parentPath = targetPath.getParent(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); Path testFile = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt"); String file = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile); String[] comps = GenericUtils.split(file, '/'); @@ -405,7 +409,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { public void testOpen() throws Exception { Path targetPath = detectTargetFolder(); Path parentPath = targetPath.getParent(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); Path clientFolder = lclSftp.resolve("client"); Path testFile = clientFolder.resolve("file.txt"); String file = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, testFile); @@ -458,7 +463,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { javaFile.setWritable(true, false); - try (SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write))) { + try (SftpClient.CloseableHandle h = sftp.open( + file, EnumSet.of(SftpClient.OpenMode.Truncate, SftpClient.OpenMode.Write))) { // OK should succeed assertTrue("Handle not marked as open for file=" + file, h.isOpen()); } @@ -524,7 +530,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { try (SftpClient sftp = createSftpClient(session)) { Collection<PosixFilePermission> initialPermissions = IoUtils.getPermissions(testFile); assertTrue("File does not have enough initial permissions: " + initialPermissions, - initialPermissions.containsAll(EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); + initialPermissions.containsAll( + EnumSet.of(PosixFilePermission.OWNER_READ, PosixFilePermission.OWNER_WRITE))); try (CloseableHandle handle = sendRawAttributeImpactOpen(file, sftp)) { outputDebugMessage("%s - handle=%s", getCurrentTestName(), handle); @@ -541,7 +548,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { } private CloseableHandle sendRawAttributeImpactOpen(String path, SftpClient sftpClient) throws Exception { - RawSftpClient sftp = assertObjectInstanceOf("Not a raw SFTP client used", RawSftpClient.class, sftpClient); + RawSftpClient sftp = assertObjectInstanceOf( + "Not a raw SFTP client used", RawSftpClient.class, sftpClient); Buffer buffer = new ByteArrayBuffer(path.length() + Long.SIZE, false); buffer.putString(path, StandardCharsets.UTF_8); //access @@ -573,7 +581,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { public void testInputStreamSkipAndReset() throws Exception { Path targetPath = detectTargetFolder(); Path parentPath = targetPath.getParent(); - Path localFile = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path localFile = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); Files.createDirectories(localFile.getParent()); byte[] data = (getClass().getName() + "#" + getCurrentTestName() + "[" + localFile + "]").getBytes(StandardCharsets.UTF_8); Files.write(localFile, data, StandardOpenOption.CREATE); @@ -584,7 +593,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { session.auth().verify(5L, TimeUnit.SECONDS); try (SftpClient sftp = createSftpClient(session); - InputStream stream = sftp.read(CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, localFile), OpenMode.Read)) { + InputStream stream = sftp.read( + CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, localFile), OpenMode.Read)) { assertFalse("Stream reported mark supported", stream.markSupported()); try { stream.mark(data.length); @@ -650,7 +660,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { @Override public DirectoryStream<Path> openDirectory( - ServerSession session, SftpEventListenerManager subsystem, DirectoryHandle dirHandle, Path dir, String handle) + ServerSession session, SftpEventListenerManager subsystem, + DirectoryHandle dirHandle, Path dir, String handle) throws IOException { dirHolder.set(dir); return SftpFileSystemAccessor.super.openDirectory(session, subsystem, dirHandle, dir, handle); @@ -801,8 +812,9 @@ public class SftpTest extends AbstractSftpClientTestSupport { @Override @SuppressWarnings("checkstyle:ParameterNumber") - public void read(ServerSession session, String remoteHandle, FileHandle localHandle, - long offset, byte[] data, int dataOffset, int dataLen, int readLen, Throwable thrown) { + public void read( + ServerSession session, String remoteHandle, FileHandle localHandle, long offset, + byte[] data, int dataOffset, int dataLen, int readLen, Throwable thrown) { readSize.addAndGet(readLen); if (log.isDebugEnabled()) { log.debug("read(" + session + ")[" + localHandle.getFile() + "] offset=" + offset + ", requested=" + dataLen + ", read=" + readLen); @@ -810,7 +822,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { } @Override - public void read(ServerSession session, String remoteHandle, DirectoryHandle localHandle, Map<String, Path> entries) { + public void read( + ServerSession session, String remoteHandle, DirectoryHandle localHandle, Map<String, Path> entries) { int numEntries = GenericUtils.size(entries); entriesCount.addAndGet(numEntries); @@ -945,7 +958,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { session.auth().verify(5L, TimeUnit.SECONDS); Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); CommonTestSupportUtils.deleteRecursive(lclSftp); Path parentPath = targetPath.getParent(); @@ -963,13 +977,20 @@ public class SftpTest extends AbstractSftpClientTestSupport { PropertyResolverUtils.updateProperty(clientChannel, AbstractSftpClient.WRITE_CHUNK_SIZE, Math.min(SftpClient.DEFAULT_WRITE_BUFFER_SIZE, AbstractSftpClient.DEFAULT_WRITE_CHUNK_SIZE) - Byte.MAX_VALUE); - uploadAndVerifyFile(sftp, clientFolder, dir, SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT - 1, "bufferMaxLenMinusOneFile.txt"); - uploadAndVerifyFile(sftp, clientFolder, dir, SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT, "bufferMaxLenFile.txt"); - uploadAndVerifyFile(sftp, clientFolder, dir, SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT + 1, "bufferMaxLenPlusOneFile.txt"); - uploadAndVerifyFile(sftp, clientFolder, dir, (int) (1.5 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT), "1point5BufferMaxLenFile.txt"); - uploadAndVerifyFile(sftp, clientFolder, dir, (2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) - 1, "2TimesBufferMaxLenMinusOneFile.txt"); - uploadAndVerifyFile(sftp, clientFolder, dir, 2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT, "2TimesBufferMaxLenFile.txt"); - uploadAndVerifyFile(sftp, clientFolder, dir, (2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) + 1, "2TimesBufferMaxLenPlusOneFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT - 1, "bufferMaxLenMinusOneFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT, "bufferMaxLenFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT + 1, "bufferMaxLenPlusOneFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + (int) (1.5 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT), "1point5BufferMaxLenFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + (2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) - 1, "2TimesBufferMaxLenMinusOneFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + 2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT, "2TimesBufferMaxLenFile.txt"); + uploadAndVerifyFile(sftp, clientFolder, dir, + (2 * SshConstants.SSH_REQUIRED_TOTAL_PACKET_LENGTH_SUPPORT) + 1, "2TimesBufferMaxLenPlusOneFile.txt"); uploadAndVerifyFile(sftp, clientFolder, dir, 200000, "largerFile.txt"); // test erroneous calls that check for negative values @@ -986,7 +1007,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { // generate random file and upload it String randomData = randomString(5); byte[] randomBytes = randomData.getBytes(StandardCharsets.UTF_8); - try (SftpClient.CloseableHandle handle = sftp.open(filePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) { + try (SftpClient.CloseableHandle handle = sftp.open( + filePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) { try { sftp.write(handle, -1, randomBytes, 0, 0); fail("should not have been able to write file with invalid file offset for " + filePath); @@ -1023,11 +1045,14 @@ public class SftpTest extends AbstractSftpClientTestSupport { assertFalse("File should not be there: " + file.toString(), Files.exists(file)); } - private void uploadAndVerifyFile(SftpClient sftp, Path clientFolder, String remoteDir, int size, String filename) throws Exception { + private void uploadAndVerifyFile( + SftpClient sftp, Path clientFolder, String remoteDir, int size, String filename) + throws Exception { // generate random file and upload it String remotePath = remoteDir + "/" + filename; String randomData = randomString(size); - try (SftpClient.CloseableHandle handle = sftp.open(remotePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) { + try (SftpClient.CloseableHandle handle = sftp.open( + remotePath, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) { sftp.write(handle, 0, randomData.getBytes(StandardCharsets.UTF_8), 0, randomData.length()); } @@ -1046,7 +1071,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { String d = getCurrentTestName() + "\n"; Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); CommonTestSupportUtils.deleteRecursive(lclSftp); Path target = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt"); @@ -1072,7 +1098,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { @Test public void testReadWriteWithOffset() throws Exception { Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); CommonTestSupportUtils.deleteRecursive(lclSftp); Path localPath = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt"); @@ -1150,7 +1177,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { @Test public void testRename() throws Exception { Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); CommonTestSupportUtils.deleteRecursive(lclSftp); Path parentPath = targetPath.getParent(); @@ -1348,7 +1376,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { } catch (SocketTimeoutException | EOFException | WindowClosedException | SshChannelClosedException e) { // expected - ignored } finally { - PropertyResolverUtils.updateProperty(session, SftpClient.SFTP_CHANNEL_OPEN_TIMEOUT, SftpClient.DEFAULT_CHANNEL_OPEN_TIMEOUT); + PropertyResolverUtils.updateProperty( + session, SftpClient.SFTP_CHANNEL_OPEN_TIMEOUT, SftpClient.DEFAULT_CHANNEL_OPEN_TIMEOUT); } } finally { sshd.setSubsystemFactories(factories); @@ -1357,7 +1386,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { private void testClient(FactoryManager manager, SftpClient sftp) throws Exception { Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); + Path lclSftp = CommonTestSupportUtils.resolve( + targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName()); CommonTestSupportUtils.deleteRecursive(lclSftp); Path parentPath = targetPath.getParent(); @@ -1366,7 +1396,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { sftp.mkdir(dir); String file = dir + "/" + getCurrentTestName() + "-file.txt"; - try (SftpClient.CloseableHandle h = sftp.open(file, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) { + try (SftpClient.CloseableHandle h = sftp.open( + file, EnumSet.of(SftpClient.OpenMode.Write, SftpClient.OpenMode.Create))) { byte[] d = "0123456789\n".getBytes(StandardCharsets.UTF_8); sftp.write(h, 0, d, 0, d.length); sftp.write(h, d.length, d, 0, d.length); @@ -1466,7 +1497,8 @@ public class SftpTest extends AbstractSftpClientTestSupport { } @Override - public void linked(ServerSession session, Path src, Path target, boolean symLink, Throwable thrown) { + public void linked( + ServerSession session, Path src, Path target, boolean symLink, Throwable thrown) { LinkData data = linkDataHolder.get(); assertNotNull("No previous linking call", data); assertSame("Mismatched source", data.getSource(), src); @@ -1537,44 +1569,6 @@ public class SftpTest extends AbstractSftpClientTestSupport { assertNotNull("No symlink signalled", linkDataHolder.getAndSet(null)); } - @Test // see SSHD-697 - public void testFileChannel() throws IOException { - Path targetPath = detectTargetFolder(); - Path lclSftp = CommonTestSupportUtils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName()); - Path lclFile = lclSftp.resolve(getCurrentTestName() + ".txt"); - Files.deleteIfExists(lclFile); - byte[] expected = (getClass().getName() + "#" + getCurrentTestName() + "(" + new Date() + ")").getBytes(StandardCharsets.UTF_8); - - try (ClientSession session = client.connect(getCurrentTestName(), TEST_LOCALHOST, port) - .verify(7L, TimeUnit.SECONDS) - .getSession()) { - session.addPasswordIdentity(getCurrentTestName()); - session.auth().verify(5L, TimeUnit.SECONDS); - - try (SftpClient sftp = createSftpClient(session)) { - Path parentPath = targetPath.getParent(); - String remFilePath = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, lclFile); - - try (FileChannel fc = sftp.openRemotePathChannel( - remFilePath, EnumSet.of(StandardOpenOption.CREATE, StandardOpenOption.READ, StandardOpenOption.WRITE))) { - int writeLen = fc.write(ByteBuffer.wrap(expected)); - assertEquals("Mismatched written length", expected.length, writeLen); - - FileChannel fcPos = fc.position(0L); - assertSame("Mismatched positioned file channel", fc, fcPos); - - byte[] actual = new byte[expected.length]; - int readLen = fc.read(ByteBuffer.wrap(actual)); - assertEquals("Mismatched read len", writeLen, readLen); - assertArrayEquals("Mismatched read data", expected, actual); - } - } - } - - byte[] actual = Files.readAllBytes(lclFile); - assertArrayEquals("Mismatched persisted data", expected, actual); - } - @Test // see SSHD-903 public void testForcedVersionNegotiation() throws Exception { PropertyResolverUtils.updateProperty(sshd, SftpSubsystemEnvironment.SFTP_VERSION, SftpConstants.SFTP_V3); @@ -1601,7 +1595,7 @@ public class SftpTest extends AbstractSftpClientTestSupport { bos.write(buffer, 0, count); } - return bos.toString(); + return bos.toString(StandardCharsets.UTF_8.name()); } finally { c.disconnect(); }