This is an automated email from the ASF dual-hosted git repository.

twolf pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mina-sshd.git

commit f93cd6b59fe580bf4a83040108ea4286f5025cbf
Author: Thomas Wolf <tw...@apache.org>
AuthorDate: Thu Jul 29 00:21:37 2021 +0200

    [SSHD-1188] SFTP: add a test for renaming a file
    
    If the target already exists, a plain rename must fail. For SFTP >= V5,
    a rename with CopyMode.Overwrite shall succeed. Note that the behavior
    with CopyMode.Atomic is platform dependent; it's mapped internally to
    java.nio.file.Files.move() with StandardCopyOption.ATOMIC_MOVE, for
    which the javadoc says
    
    "If the target file exists then it is implementation specific if
    the existing file is replaced or this method fails by throwing an
    IOException."
    
    This is fine; the SFTP RFC draft, version 13, allows this behavior for
    atomic renames.[1]
    
    [1] 
https://datatracker.ietf.org/doc/html/draft-ietf-secsh-filexfer-13#section-8.3
---
 .../apache/sshd/sftp/client/SftpVersionsTest.java  | 38 ++++++++++++++++++++++
 1 file changed, 38 insertions(+)

diff --git 
a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java 
b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java
index 7ce296e..8a926a9 100644
--- a/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java
+++ b/sshd-sftp/src/test/java/org/apache/sshd/sftp/client/SftpVersionsTest.java
@@ -20,6 +20,7 @@
 package org.apache.sshd.sftp.client;
 
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.OutputStream;
 import java.nio.charset.StandardCharsets;
 import java.nio.file.Files;
@@ -48,6 +49,7 @@ import org.apache.sshd.client.session.ClientSession;
 import org.apache.sshd.common.util.GenericUtils;
 import org.apache.sshd.common.util.MapEntryUtils;
 import org.apache.sshd.common.util.MapEntryUtils.NavigableMapBuilder;
+import org.apache.sshd.common.util.io.IoUtils;
 import org.apache.sshd.server.channel.ChannelSession;
 import org.apache.sshd.server.command.Command;
 import org.apache.sshd.server.session.ServerSession;
@@ -55,6 +57,7 @@ import org.apache.sshd.server.subsystem.SubsystemFactory;
 import org.apache.sshd.sftp.SftpModuleProperties;
 import org.apache.sshd.sftp.client.SftpClient.Attributes;
 import org.apache.sshd.sftp.client.SftpClient.CloseableHandle;
+import org.apache.sshd.sftp.client.SftpClient.CopyMode;
 import org.apache.sshd.sftp.client.SftpClient.DirEntry;
 import org.apache.sshd.sftp.client.SftpClient.OpenMode;
 import org.apache.sshd.sftp.common.SftpConstants;
@@ -159,6 +162,41 @@ public class SftpVersionsTest extends 
AbstractSftpClientTestSupport {
     }
 
     @Test
+    public void testSftpRenameNoReplace() throws Exception {
+        Path targetPath = detectTargetFolder();
+        Path lclSftp = CommonTestSupportUtils.resolve(targetPath, 
SftpConstants.SFTP_SUBSYSTEM_NAME,
+                getClass().getSimpleName());
+        Path lclParent = assertHierarchyTargetFolderExists(lclSftp);
+        Path aFile = lclParent.resolve(getCurrentTestName() + "-" + 
getTestedVersion() + "-a.txt");
+        Files.write(aFile, Collections.singleton("a"));
+        Path bFile = lclParent.resolve(getCurrentTestName() + "-" + 
getTestedVersion() + "-b.txt");
+        Files.write(bFile, Collections.singleton("b"));
+
+        Path parentPath = targetPath.getParent();
+        String aPath = 
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, aFile);
+        String bPath = 
CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, bFile);
+        try (ClientSession session = createAuthenticatedClientSession();
+             SftpClient sftp = createSftpClient(session, getTestedVersion())) {
+            SftpException ex = assertThrows(SftpException.class, () -> 
sftp.rename(aPath, bPath));
+            assertEquals(SftpConstants.SSH_FX_FILE_ALREADY_EXISTS, 
ex.getStatus());
+            if (getTestedVersion() >= SftpConstants.SFTP_V5) {
+                // For CopyMode.Atomic we use StandardCopyOptions.ATOMIC_MOVE. 
It is implementation defined whether an
+                // atomic move overwrites an already existing file. See 
javadoc of Files.move().
+                sftp.rename(aPath, bPath, CopyMode.Overwrite);
+                assertTrue(Files.notExists(aFile));
+                try (InputStream in = sftp.read(bPath)) {
+                    List<String> lines = IoUtils.readAllLines(in);
+                    assertEquals(1, lines.size());
+                    assertEquals("a", lines.get(0));
+                }
+            } else {
+                assertThrows(UnsupportedOperationException.class, () -> 
sftp.rename(aPath, bPath, CopyMode.Atomic));
+                assertThrows(UnsupportedOperationException.class, () -> 
sftp.rename(aPath, bPath, CopyMode.Overwrite));
+            }
+        }
+    }
+
+    @Test
     public void testSftpVersionSelector() throws Exception {
         try (ClientSession session = createAuthenticatedClientSession();
              SftpClient sftp = createSftpClient(session, getTestedVersion())) {

Reply via email to