Skip to content

Commit

Permalink
[SSHD-525] Server side implementation of [email protected]
Browse files Browse the repository at this point in the history
  • Loading branch information
gnodet committed May 10, 2021
1 parent 4dad0d7 commit 9a724be
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 2 deletions.
2 changes: 1 addition & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

## Minor code helpers

* [SSHD-525](https://issues.apache.org/jira/browse/SSHD-525) Added support for SFTP **client-side** ["[email protected]"
* [SSHD-525](https://issues.apache.org/jira/browse/SSHD-525) Added support for SFTP `[email protected]`
extension](http://cvsweb.openbsd.org/cgi-bin/cvsweb/src/usr.bin/ssh/PROTOCOL?rev=1.28&content-type=text/x-cvsweb-markup) - see section 3.3
* [SSHD-1083](https://issues.apache.org/jira/browse/SSHD-1083) Relaxed required `Nio2Connector/Acceptor` required constructor arguments
* [SSHD-1085](https://issues.apache.org/jira/browse/SSHD-1085) Added `CliLogger` + more verbosity on `SshClientMain`
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@
import org.apache.sshd.sftp.common.extensions.openssh.FsyncExtensionParser;
import org.apache.sshd.sftp.common.extensions.openssh.HardLinkExtensionParser;
import org.apache.sshd.sftp.common.extensions.openssh.LSetStatExtensionParser;
import org.apache.sshd.sftp.common.extensions.openssh.PosixRenameExtensionParser;

/**
* @author <a href="mailto:[email protected]">Apache MINA SSHD Project</a>
Expand Down Expand Up @@ -130,7 +131,8 @@ NavigableMapBuilder.<String, OptionalFeature> builder()
Arrays.asList(
new OpenSSHExtension(FsyncExtensionParser.NAME, "1"),
new OpenSSHExtension(HardLinkExtensionParser.NAME, "1"),
new OpenSSHExtension(LSetStatExtensionParser.NAME, "1")));
new OpenSSHExtension(LSetStatExtensionParser.NAME, "1"),
new OpenSSHExtension(PosixRenameExtensionParser.NAME, "1")));

public static final List<String> DEFAULT_OPEN_SSH_EXTENSIONS_NAMES = Collections.unmodifiableList(
NamedResource.getNameList(DEFAULT_OPEN_SSH_EXTENSIONS));
Expand Down Expand Up @@ -1226,6 +1228,23 @@ protected void doRename(int id, String oldPath, String newPath, Collection<CopyO
listener.moved(session, o, n, opts, null);
}

// see https://github.com/openssh/openssh-portable/blob/master/PROTOCOL section 3.3
protected void doPosixRename(Buffer buffer, int id) throws IOException {
String oldPath = buffer.getString();
String newPath = buffer.getString();
try {
int flags = SftpConstants.SSH_FXP_RENAME_ATOMIC | SftpConstants.SSH_FXP_RENAME_OVERWRITE;
doRename(id, oldPath, newPath, flags);
} catch (IOException | RuntimeException e) {
sendStatus(prepareReply(buffer), id, e,
SftpConstants.SSH_FXP_EXTENDED, SftpConstants.SSH_FXP_RENAME,
oldPath, newPath);
return;
}

sendStatus(prepareReply(buffer), id, SftpConstants.SSH_FX_OK, "");
}

// see https://tools.ietf.org/html/draft-ietf-secsh-filexfer-extensions-00#section-7
protected void doCopyData(Buffer buffer, int id) throws IOException {
String readHandle = buffer.getString();
Expand Down Expand Up @@ -1740,6 +1759,9 @@ protected void executeExtendedCommand(Buffer buffer, int id, String extension) t
case LSetStatExtensionParser.NAME:
doSetStat(buffer, id, extension, -1, Boolean.FALSE);
break;
case PosixRenameExtensionParser.NAME:
doPosixRename(buffer, id);
break;
default:
doUnsupportedExtension(buffer, id, extension);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
package org.apache.sshd.sftp.client.extensions.openssh.helpers;

import java.io.IOException;
import java.io.OutputStream;
import java.io.StreamCorruptedException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
Expand All @@ -41,10 +42,12 @@
import org.apache.sshd.sftp.client.SftpClient;
import org.apache.sshd.sftp.client.SftpClient.CloseableHandle;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHFsyncExtension;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHPosixRenameExtension;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHStatExtensionInfo;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHStatHandleExtension;
import org.apache.sshd.sftp.client.extensions.openssh.OpenSSHStatPathExtension;
import org.apache.sshd.sftp.common.SftpConstants;
import org.apache.sshd.sftp.common.SftpException;
import org.apache.sshd.sftp.common.extensions.openssh.AbstractOpenSSHExtensionParser.OpenSSHExtension;
import org.apache.sshd.sftp.common.extensions.openssh.FstatVfsExtensionParser;
import org.apache.sshd.sftp.common.extensions.openssh.StatVfsExtensionParser;
Expand All @@ -70,6 +73,44 @@ public void setUp() throws Exception {
setupServer();
}

@Test
public void testPosixRename() throws IOException {
Path targetPath = detectTargetFolder();
Path lclSftp = CommonTestSupportUtils.resolve(
targetPath, SftpConstants.SFTP_SUBSYSTEM_NAME, getClass().getSimpleName(), getCurrentTestName());
CommonTestSupportUtils.deleteRecursive(lclSftp);

Path parentPath = targetPath.getParent();
Path clientFolder = assertHierarchyTargetFolderExists(lclSftp.resolve("client"));
try (SftpClient sftp = createSingleSessionClient()) {
OpenSSHPosixRenameExtension rename = assertExtensionCreated(sftp, OpenSSHPosixRenameExtension.class);

Path file1 = clientFolder.resolve("file-1.txt");
String file1Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, file1);
try (OutputStream os = sftp.write(file1Path, SftpClient.MIN_WRITE_BUFFER_SIZE)) {
os.write((getCurrentTestName() + "\n").getBytes(StandardCharsets.UTF_8));
}

Path file2 = clientFolder.resolve("file-2.txt");
String file2Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, file2);
Path file3 = clientFolder.resolve("file-3.txt");
String file3Path = CommonTestSupportUtils.resolveRelativeRemotePath(parentPath, file3);
try {
rename.posixRename(file2Path, file3Path);
fail("Unxpected rename success of " + file2Path + " => " + file3Path);
} catch (SftpException e) {
assertEquals("Mismatched status for failed rename of " + file2Path + " => " + file3Path,
SftpConstants.SSH_FX_NO_SUCH_FILE, e.getStatus());
}

try (OutputStream os = sftp.write(file2Path, SftpClient.MIN_WRITE_BUFFER_SIZE)) {
os.write("h".getBytes(StandardCharsets.UTF_8));
}

rename.posixRename(file1Path, file2Path);
}
}

@Test
public void testFsync() throws IOException {
Path targetPath = detectTargetFolder();
Expand Down

0 comments on commit 9a724be

Please sign in to comment.