Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
plugins {
id "java"
id "groovy"
id "maven"
id "idea"
id "signing"
id "osgi"
id "org.ajoberstar.release-opinion" version "1.4.0-rc.1"
id "org.ajoberstar.release-opinion" version "1.4.2"
id "com.github.hierynomus.license" version "0.12.1"
}

Expand Down Expand Up @@ -72,6 +73,7 @@ dependencies {
compile "net.vrallev.ecc:ecc-25519-java:1.0.1"

testCompile "junit:junit:4.11"
testCompile 'org.spockframework:spock-core:1.0-groovy-2.4'
testCompile "org.mockito:mockito-core:1.9.5"
testCompile "org.apache.sshd:sshd-core:1.1.0"
testRuntime "ch.qos.logback:logback-classic:1.1.2"
Expand Down Expand Up @@ -204,4 +206,5 @@ uploadArchives {
}
}

tasks.compileGroovy.onlyIf { false }
tasks.release.dependsOn 'build', 'uploadArchives'
2 changes: 1 addition & 1 deletion src/main/java/net/schmizz/sshj/DefaultConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
102 changes: 65 additions & 37 deletions src/main/java/net/schmizz/sshj/sftp/SFTPFileTransfer.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import java.io.InputStream;
import java.io.OutputStream;
import java.util.EnumSet;
import java.util.List;

public class SFTPFileTransfer
extends AbstractFileTransfer
Expand Down Expand Up @@ -67,7 +68,7 @@ public void download(String source, String dest)
@Override
public void upload(LocalSourceFile localFile, String remotePath)
throws IOException {
new Uploader().upload(getTransferListener(), localFile, remotePath);
new Uploader(localFile, remotePath).upload(getTransferListener());
}

@Override
Expand Down Expand Up @@ -173,6 +174,31 @@ private void copyAttributes(final RemoteResourceInfo remote, final LocalDestFile

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)
Expand All @@ -182,73 +208,77 @@ private void upload(final TransferListener listener,
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,
final LocalSourceFile local,
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
return true;
} 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;
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 {
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 String prepareFile(final LocalSourceFile local, final String remote)
Expand All @@ -264,8 +294,7 @@ private String prepareFile(final LocalSourceFile local, final String remote)
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;
Expand All @@ -281,5 +310,4 @@ private FileAttributes getAttributes(LocalSourceFile local)
}

}

}
Loading