You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mina.apache.org by lg...@apache.org on 2015/08/02 11:55:23 UTC

mina-sshd git commit: [SSHD-547] Ignore offset in SFTP SSH_FXP_WRITE if file opened with SSH_FXF_APPEND_DATA access

Repository: mina-sshd
Updated Branches:
  refs/heads/master 61e637c48 -> 3eefdb3f8


[SSHD-547] Ignore offset in SFTP SSH_FXP_WRITE if file opened with SSH_FXF_APPEND_DATA access


Project: http://git-wip-us.apache.org/repos/asf/mina-sshd/repo
Commit: http://git-wip-us.apache.org/repos/asf/mina-sshd/commit/3eefdb3f
Tree: http://git-wip-us.apache.org/repos/asf/mina-sshd/tree/3eefdb3f
Diff: http://git-wip-us.apache.org/repos/asf/mina-sshd/diff/3eefdb3f

Branch: refs/heads/master
Commit: 3eefdb3f8cdf015f8f147572ed83de6390ff4bc0
Parents: 61e637c
Author: Lyor Goldstein <lg...@vmware.com>
Authored: Sun Aug 2 12:55:13 2015 +0300
Committer: Lyor Goldstein <lg...@vmware.com>
Committed: Sun Aug 2 12:55:13 2015 +0300

----------------------------------------------------------------------
 .../sshd/server/subsystem/sftp/FileHandle.java  | 16 +++++
 .../server/subsystem/sftp/SftpSubsystem.java    |  6 +-
 .../sshd/client/subsystem/sftp/SftpTest.java    | 64 ++++++++++++++++++--
 3 files changed, 80 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3eefdb3f/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
index 92f9346..49379de 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/FileHandle.java
@@ -33,10 +33,12 @@ import java.util.List;
 import java.util.Map;
 import java.util.Set;
 
+import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_APPEND_DATA;
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_READ_ATTRIBUTES;
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_READ_DATA;
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_WRITE_ATTRIBUTES;
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.ACE4_WRITE_DATA;
+
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_ACCESS_DISPOSITION;
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_APPEND_DATA;
 import static org.apache.sshd.common.subsystem.sftp.SftpConstants.SSH_FXF_CREATE_NEW;
@@ -123,6 +125,10 @@ public class FileHandle extends Handle {
         return access;
     }
 
+    public boolean isOpenAppend() {
+        return ACE4_APPEND_DATA == (getAccessMask() & ACE4_APPEND_DATA);
+    }
+
     public int read(byte[] data, long offset) throws IOException {
         return read(data, 0, data.length, offset);
     }
@@ -138,6 +144,15 @@ public class FileHandle extends Handle {
         return read;
     }
 
+    public void append(byte[] data) throws IOException {
+        append(data, 0, data.length);
+    }
+
+    public void append(byte[] data, int doff, int length) throws IOException {
+        FileChannel channel = getFileChannel();
+        write(data, doff, length, channel.size());
+    }
+
     public void write(byte[] data, long offset) throws IOException {
         write(data, 0, data.length, offset);
     }
@@ -148,6 +163,7 @@ public class FileHandle extends Handle {
             channel.position(offset);
             pos = offset;
         }
+
         channel.write(ByteBuffer.wrap(data, doff, length));
         pos += length;
     }

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3eefdb3f/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
index 1ae19ee..607a9b8 100644
--- a/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
+++ b/sshd-core/src/main/java/org/apache/sshd/server/subsystem/sftp/SftpSubsystem.java
@@ -1879,7 +1879,11 @@ public class SftpSubsystem extends AbstractLoggingBean implements Command, Runna
             throw new IllegalStateException("Not enough buffer data for writing to " + fh + ": required=" + length + ", available=" + remaining);
         }
 
-        fh.write(data, doff, length, offset);
+        if (fh.isOpenAppend()) {
+            fh.append(data, doff, length);
+        } else {
+            fh.write(data, doff, length, offset);
+        }
     }
 
     protected void doRead(Buffer buffer, int id) throws IOException {

http://git-wip-us.apache.org/repos/asf/mina-sshd/blob/3eefdb3f/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
----------------------------------------------------------------------
diff --git a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
index 6fd49d8..d551113 100644
--- a/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
+++ b/sshd-core/src/test/java/org/apache/sshd/client/subsystem/sftp/SftpTest.java
@@ -35,6 +35,7 @@ import java.nio.file.FileSystem;
 import java.nio.file.Files;
 import java.nio.file.Path;
 import java.nio.file.Paths;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.EnumSet;
 import java.util.Iterator;
@@ -116,6 +117,59 @@ public class SftpTest extends AbstractSftpClientTestSupport {
         Thread.sleep(5 * 60000);
     }
 
+    @Test   // see SSHD-547
+    public void testWriteOffsetIgnoredForAppendMode() throws IOException {
+        Path targetPath = detectTargetFolder().toPath();
+        Path parentPath = targetPath.getParent();
+        Path lclSftp = Utils.resolve(targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
+        Path testFile = assertHierarchyTargetFolderExists(lclSftp).resolve("file.txt");
+        Files.deleteIfExists(testFile);
+
+        byte[] expectedRandom = new byte[Byte.MAX_VALUE];
+        Factory<? extends Random> factory = sshd.getRandomFactory();
+        Random rnd = factory.create();
+        rnd.fill(expectedRandom);
+
+        byte[] expectedText = (getClass().getName() + "#" + getCurrentTestName()).getBytes(StandardCharsets.UTF_8);
+        try (SshClient client = SshClient.setUpDefaultClient()) {
+            client.start();
+
+            try (ClientSession session = client.connect(getCurrentTestName(), "localhost", port).verify(7L, TimeUnit.SECONDS).getSession()) {
+                session.addPasswordIdentity(getCurrentTestName());
+                session.auth().verify(5L, TimeUnit.SECONDS);
+
+                try (SftpClient sftp = session.createSftpClient()) {
+                    String file = Utils.resolveRelativeRemotePath(parentPath, testFile);
+
+                    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);
+                        assertEquals("Incomplete random data read", expectedRandom.length, readLen);
+                        assertArrayEquals("Mismatched read random data", expectedRandom, actualRandom);
+
+                        sftp.write(handle, 3777347L, expectedText);
+                        byte[] actualText = new byte[expectedText.length];
+                        readLen = sftp.read(handle, actualRandom.length, actualText);
+                        assertEquals("Incomplete text data read", actualText.length, readLen);
+                        assertArrayEquals("Mismatched read text data", expectedText, actualText);
+                    }
+                }
+            } finally {
+                client.stop();
+            }
+        }
+
+        byte[] actualBytes = Files.readAllBytes(testFile);
+        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);
+
+        byte[] actualText = Arrays.copyOfRange(actualBytes, expectedRandom.length, actualBytes.length);
+        assertArrayEquals("Mismatched text part", expectedText, actualText);
+    }
+
     @Test   // see SSHD-545
     public void testReadBufferLimit() throws Exception {
         Path targetPath = detectTargetFolder().toPath();
@@ -145,7 +199,7 @@ public class SftpTest extends AbstractSftpClientTestSupport {
                     try(CloseableHandle handle = sftp.open(file, OpenMode.Read)) {
                         int readLen = sftp.read(handle, 0L, actual);
                         assertEquals("Mismatched read len", maxAllowed, readLen);
-                        
+
                         for (int index = 0; index < readLen; index++) {
                             byte expByte = expected[index], actByte = actual[index];
                             if (expByte != actByte) {
@@ -868,13 +922,13 @@ public class SftpTest extends AbstractSftpClientTestSupport {
         /*
          * NOTE !!! according to Jsch documentation
          * (see http://epaul.github.io/jsch-documentation/simple.javadoc/com/jcraft/jsch/ChannelSftp.html#current-directory)
-         * 
-         * 
+         *
+         *
          * 		This sftp client has the concept of a current local directory and
          * 		a current remote directory. These are not inherent to the protocol,
          *  	but are used implicitly for all path-based commands sent to the server
          *  	for the remote directory) or accessing the local file system (for the local directory).
-         *  
+         *
          *  Therefore we are using "absolute" remote files for this test
          */
         Path parentPath = targetPath.getParent();
@@ -897,7 +951,7 @@ public class SftpTest extends AbstractSftpClientTestSupport {
 
             assertTrue("Symlink not created: " + linkPath, Files.exists(linkPath));
             assertEquals("Mismatched link data in " + remLinkPath, data, readFile(remLinkPath));
-    
+
             String str1 = c.readlink(remLinkPath);
             String str2 = c.realpath(remSrcPath);
             assertEquals("Mismatched link vs. real path", str1, str2);