mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-06 23:30:55 +03:00
Ensure that same name subdirs aren't omitted when doing SFTP (#253)
* Updated version string in config * Fixed #252 with backwards compatible behaviour * Fixed logic and expanded test
This commit is contained in:
@@ -84,7 +84,7 @@ public class DefaultConfig
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private static final String VERSION = "SSHJ_0_14_0";
|
||||
private static final String VERSION = "SSHJ_0_16_0";
|
||||
|
||||
public DefaultConfig() {
|
||||
setVersion(VERSION);
|
||||
|
||||
@@ -29,6 +29,7 @@ import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
public class SFTPFileTransfer
|
||||
extends AbstractFileTransfer
|
||||
@@ -67,7 +68,7 @@ public class SFTPFileTransfer
|
||||
@Override
|
||||
public void upload(LocalSourceFile localFile, String remotePath)
|
||||
throws IOException {
|
||||
new Uploader().upload(getTransferListener(), localFile, remotePath);
|
||||
new Uploader(localFile, remotePath).upload(getTransferListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -173,6 +174,31 @@ public class SFTPFileTransfer
|
||||
|
||||
private class Uploader {
|
||||
|
||||
private final LocalSourceFile source;
|
||||
private final String remote;
|
||||
|
||||
private Uploader(final LocalSourceFile source, final String remote) {
|
||||
this.source = source;
|
||||
this.remote = remote;
|
||||
}
|
||||
|
||||
private void upload(final TransferListener listener) throws IOException {
|
||||
if (source.isDirectory()) {
|
||||
makeDirIfNotExists(remote); // Ensure that the directory exists
|
||||
uploadDir(listener.directory(source.getName()), source, remote);
|
||||
setAttributes(source, remote);
|
||||
} else if (source.isFile() && isDirectory(remote)) {
|
||||
String adjustedRemote = engine.getPathHelper().adjustForParent(this.remote, source.getName());
|
||||
uploadFile(listener.file(source.getName(), source.getLength()), source, adjustedRemote);
|
||||
setAttributes(source, adjustedRemote);
|
||||
} else if (source.isFile()) {
|
||||
uploadFile(listener.file(source.getName(), source.getLength()), source, remote);
|
||||
setAttributes(source, remote);
|
||||
} else {
|
||||
throw new IOException(source + " is not a file or directory");
|
||||
}
|
||||
}
|
||||
|
||||
private void upload(final TransferListener listener,
|
||||
final LocalSourceFile local,
|
||||
final String remote)
|
||||
@@ -182,20 +208,26 @@ public class SFTPFileTransfer
|
||||
adjustedPath = uploadDir(listener.directory(local.getName()), local, remote);
|
||||
} else if (local.isFile()) {
|
||||
adjustedPath = uploadFile(listener.file(local.getName(), local.getLength()), local, remote);
|
||||
} else
|
||||
} else {
|
||||
throw new IOException(local + " is not a file or directory");
|
||||
if (getPreserveAttributes())
|
||||
engine.setAttributes(adjustedPath, getAttributes(local));
|
||||
}
|
||||
setAttributes(local, adjustedPath);
|
||||
}
|
||||
|
||||
private void setAttributes(LocalSourceFile local, String remotePath) throws IOException {
|
||||
if (getPreserveAttributes()) {
|
||||
engine.setAttributes(remotePath, getAttributes(local));
|
||||
}
|
||||
}
|
||||
|
||||
private String uploadDir(final TransferListener listener,
|
||||
final LocalSourceFile local,
|
||||
final String remote)
|
||||
throws IOException {
|
||||
final String adjusted = prepareDir(local, remote);
|
||||
makeDirIfNotExists(remote);
|
||||
for (LocalSourceFile f : local.getChildren(getUploadFilter()))
|
||||
upload(listener, f, adjusted);
|
||||
return adjusted;
|
||||
upload(listener, f, engine.getPathHelper().adjustForParent(remote, f.getName()));
|
||||
return remote;
|
||||
}
|
||||
|
||||
private String uploadFile(final StreamCopier.Listener listener,
|
||||
@@ -203,52 +235,50 @@ public class SFTPFileTransfer
|
||||
final String remote)
|
||||
throws IOException {
|
||||
final String adjusted = prepareFile(local, remote);
|
||||
final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE,
|
||||
OpenMode.CREAT,
|
||||
OpenMode.TRUNC));
|
||||
try {
|
||||
final InputStream fis = local.getInputStream();
|
||||
final RemoteFile.RemoteFileOutputStream rfos = rf.new RemoteFileOutputStream(0, 16);
|
||||
try {
|
||||
try (RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE, OpenMode.CREAT, OpenMode.TRUNC))) {
|
||||
try (InputStream fis = local.getInputStream();
|
||||
RemoteFile.RemoteFileOutputStream rfos = rf.new RemoteFileOutputStream(0, 16)) {
|
||||
new StreamCopier(fis, rfos)
|
||||
.bufSize(engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead())
|
||||
.keepFlushing(false)
|
||||
.listener(listener)
|
||||
.copy();
|
||||
} finally {
|
||||
fis.close();
|
||||
rfos.close();
|
||||
}
|
||||
} finally {
|
||||
rf.close();
|
||||
}
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
private String prepareDir(final LocalSourceFile local, final String remote)
|
||||
throws IOException {
|
||||
final FileAttributes attrs;
|
||||
private boolean makeDirIfNotExists(final String remote) throws IOException {
|
||||
try {
|
||||
attrs = engine.stat(remote);
|
||||
FileAttributes attrs = engine.stat(remote);
|
||||
if (attrs.getMode().getType() != FileMode.Type.DIRECTORY) {
|
||||
throw new IOException(remote + " exists and should be a directory, but was a " + attrs.getMode().getType());
|
||||
}
|
||||
// Was not created, but existed.
|
||||
return false;
|
||||
} catch (SFTPException e) {
|
||||
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
|
||||
log.debug("probeDir: {} does not exist, creating", remote);
|
||||
log.debug("makeDir: {} does not exist, creating", remote);
|
||||
engine.makeDir(remote);
|
||||
return remote;
|
||||
} else
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY)
|
||||
if (engine.getPathHelper().getComponents(remote).getName().equals(local.getName())) {
|
||||
log.debug("probeDir: {} already exists", remote);
|
||||
return remote;
|
||||
return true;
|
||||
} else {
|
||||
log.debug("probeDir: {} already exists, path adjusted for {}", remote, local.getName());
|
||||
return prepareDir(local, engine.getPathHelper().adjustForParent(remote, local.getName()));
|
||||
throw e;
|
||||
}
|
||||
else
|
||||
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isDirectory(final String remote) throws IOException {
|
||||
try {
|
||||
FileAttributes attrs = engine.stat(remote);
|
||||
return attrs.getMode().getType() == FileMode.Type.DIRECTORY;
|
||||
} catch (SFTPException e) {
|
||||
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
|
||||
log.debug("isDir: {} does not exist", remote);
|
||||
return false;
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String prepareFile(final LocalSourceFile local, final String remote)
|
||||
@@ -264,8 +294,7 @@ public class SFTPFileTransfer
|
||||
throw e;
|
||||
}
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY) {
|
||||
log.debug("probeFile: {} was directory, path adjusted for {}", remote, local.getName());
|
||||
return engine.getPathHelper().adjustForParent(remote, local.getName());
|
||||
throw new IOException("Trying to upload file " + local.getName() + " to path " + remote + " but that is a directory");
|
||||
} else {
|
||||
log.debug("probeFile: {} is a {} file that will be replaced", remote, attrs.getMode().getType());
|
||||
return remote;
|
||||
@@ -281,5 +310,4 @@ public class SFTPFileTransfer
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user