in sshd-scp/src/main/java/org/apache/sshd/scp/client/ScpRemote2RemoteTransferHelper.java [273:373]
protected void handleDirectoryTransferRequest(
String srcPath, InputStream srcIn, OutputStream srcOut,
String dstPath, InputStream dstIn, OutputStream dstOut,
int depth, ScpTimestampCommandDetails dirTime, String header)
throws IOException {
if (header.charAt(0) != ScpReceiveDirCommandDetails.COMMAND_NAME) {
throw new IllegalArgumentException("Invalid file transfer request: " + header);
}
ScpIoUtils.writeLine(dstOut, csOut, header);
ScpAckInfo ackInfo = transferStatusCode(header, dstIn, srcOut);
ackInfo.validateCommandStatusCode("[DST@" + depth + "] " + header, "handleDirectoryTransferRequest");
ScpReceiveDirCommandDetails dirDetails = new ScpReceiveDirCommandDetails(header);
signalReceivedCommand(dirDetails);
String dirName = dirDetails.getName();
// 1st command refers to the first path component of the original source/destination
String source = (depth == 0) ? srcPath : SelectorUtils.concatPaths(srcPath, dirName, '/');
String destination = (depth == 0) ? dstPath : SelectorUtils.concatPaths(dstPath, dirName, '/');
ClientSession srcSession = getSourceSession();
ClientSession dstSession = getDestinationSession();
if (listener != null) {
listener.startDirectDirectoryTransfer(srcSession, source, dstSession, destination, dirTime, dirDetails);
}
try {
for (boolean debugEnabled = log.isDebugEnabled(), dirEndSignal = false;
!dirEndSignal;
debugEnabled = log.isDebugEnabled()) {
Object data = receiveNextCmd("handleDirectoryTransferRequest", srcIn);
if (data instanceof ScpAckInfo) {
throw new StreamCorruptedException("Unexpected ACK instead of header: " + data);
}
header = (String) data;
if (debugEnabled) {
log.debug("handleDirectoryTransferRequest({})[depth={}] {} => {}: header={}",
this, depth, source, destination, header);
}
ScpTimestampCommandDetails time = null;
char cmdName = header.charAt(0);
if (cmdName == ScpTimestampCommandDetails.COMMAND_NAME) {
// Pass along the "T<mtime> 0 <atime> 0" and wait for response
time = new ScpTimestampCommandDetails(header);
signalReceivedCommand(time);
header = transferTimestampCommand(source, srcIn, srcOut, destination, dstIn, dstOut, header);
if (debugEnabled) {
log.debug("handleDirectoryTransferRequest({})[depth={}] {} => {}: header={}",
this, depth, source, destination, header);
}
cmdName = header.charAt(0);
}
switch (cmdName) {
case ScpReceiveFileCommandDetails.COMMAND_NAME:
case ScpReceiveDirCommandDetails.COMMAND_NAME: {
ScpPathCommandDetailsSupport subPathDetails = (cmdName == ScpReceiveFileCommandDetails.COMMAND_NAME)
? new ScpReceiveFileCommandDetails(header)
: new ScpReceiveDirCommandDetails(header);
String name = subPathDetails.getName();
String srcSubPath = SelectorUtils.concatPaths(source, name, '/');
String dstSubPath = SelectorUtils.concatPaths(destination, name, '/');
if (cmdName == ScpReceiveFileCommandDetails.COMMAND_NAME) {
handleFileTransferRequest(srcSubPath, srcIn, srcOut, dstSubPath, dstIn, dstOut, time, header);
} else {
handleDirectoryTransferRequest(srcSubPath, srcIn, srcOut, dstSubPath, dstIn, dstOut, depth + 1,
time, header);
}
break;
}
case ScpDirEndCommandDetails.COMMAND_NAME: {
ScpIoUtils.writeLine(dstOut, csOut, header);
ackInfo = transferStatusCode(header, dstIn, srcOut);
ackInfo.validateCommandStatusCode("[DST@" + depth + "] " + header, "handleDirectoryTransferRequest");
ScpDirEndCommandDetails details = ScpDirEndCommandDetails.parse(header);
signalReceivedCommand(details);
dirEndSignal = true;
break;
}
default:
throw new StreamCorruptedException("Unexpected file command: " + header);
}
}
} catch (IOException | RuntimeException | Error e) {
if (listener != null) {
listener.endDirectDirectoryTransfer(srcSession, source, dstSession, destination, dirTime, dirDetails, e);
}
throw e;
}
if (listener != null) {
listener.endDirectDirectoryTransfer(srcSession, source, dstSession, destination, dirTime, dirDetails, null);
}
}