mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-07 07:40:55 +03:00
* sftp / include file type information when uploading
* misc. sftp cleanups
This commit is contained in:
@@ -178,13 +178,19 @@ public final class FileAttributes {
|
||||
|
||||
public Builder withPermissions(Set<FilePermission> perms) {
|
||||
mask |= Flag.MODE.get();
|
||||
this.mode = new FileMode(FilePermission.toMask(perms));
|
||||
this.mode = new FileMode((mode != null ? mode.getTypeMask() : 0) | FilePermission.toMask(perms));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withPermissions(int perms) {
|
||||
mask |= Flag.MODE.get();
|
||||
this.mode = new FileMode(perms);
|
||||
this.mode = new FileMode((mode != null ? mode.getTypeMask() : 0) | perms);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder withType(FileMode.Type type) {
|
||||
mask |= Flag.MODE.get();
|
||||
this.mode = new FileMode(type.toMask() | (mode != null ? mode.getPermissionsMask() : 0));
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -208,7 +214,7 @@ public final class FileAttributes {
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
StringBuilder sb = new StringBuilder("[");
|
||||
final StringBuilder sb = new StringBuilder("[");
|
||||
|
||||
if (has(Flag.SIZE))
|
||||
sb.append("size=").append(size).append(";");
|
||||
|
||||
@@ -53,8 +53,8 @@ public class FileMode {
|
||||
return UNKNOWN;
|
||||
}
|
||||
|
||||
public static int toMask(Type t) {
|
||||
return t.val;
|
||||
public int toMask() {
|
||||
return val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -20,8 +20,6 @@ import net.schmizz.sshj.sftp.Response.StatusCode;
|
||||
import net.schmizz.sshj.xfer.AbstractFileTransfer;
|
||||
import net.schmizz.sshj.xfer.FileTransfer;
|
||||
import net.schmizz.sshj.xfer.FileTransferUtil;
|
||||
import net.schmizz.sshj.xfer.ModeGetter;
|
||||
import net.schmizz.sshj.xfer.ModeSetter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
@@ -59,15 +57,14 @@ public class SFTPFileTransfer
|
||||
|
||||
public void upload(String source, String dest)
|
||||
throws IOException {
|
||||
new Uploader(getModeGetter(), getUploadFilter()).upload(new File(source), dest);
|
||||
new Uploader().upload(new File(source), dest);
|
||||
}
|
||||
|
||||
public void download(String source, String dest)
|
||||
throws IOException {
|
||||
final PathComponents pathComponents = pathHelper.getComponents(source);
|
||||
final FileAttributes attributes = sftp.stat(source);
|
||||
new Downloader(getModeSetter(), getDownloadFilter())
|
||||
.download(new RemoteResourceInfo(pathComponents, attributes), new File(dest));
|
||||
new Downloader().download(new RemoteResourceInfo(pathComponents, attributes), new File(dest));
|
||||
}
|
||||
|
||||
public void setUploadFilter(FileFilter uploadFilter) {
|
||||
@@ -88,31 +85,23 @@ public class SFTPFileTransfer
|
||||
|
||||
private class Downloader {
|
||||
|
||||
private final ModeSetter modeSetter;
|
||||
private final RemoteResourceFilter filter;
|
||||
|
||||
Downloader(ModeSetter modeSetter, RemoteResourceFilter filter) {
|
||||
this.modeSetter = modeSetter;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
private void setAttributes(RemoteResourceInfo remote, File local)
|
||||
private void setAttributes(final RemoteResourceInfo remote, final File local)
|
||||
throws IOException {
|
||||
final FileAttributes attrs = remote.getAttributes();
|
||||
modeSetter.setPermissions(local, attrs.getMode().getPermissionsMask());
|
||||
if (modeSetter.preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) {
|
||||
modeSetter.setLastAccessedTime(local, attrs.getAtime());
|
||||
modeSetter.setLastModifiedTime(local, attrs.getMtime());
|
||||
getModeSetter().setPermissions(local, attrs.getMode().getPermissionsMask());
|
||||
if (getModeSetter().preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) {
|
||||
getModeSetter().setLastAccessedTime(local, attrs.getAtime());
|
||||
getModeSetter().setLastModifiedTime(local, attrs.getMtime());
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadFile(RemoteResourceInfo remote, File local)
|
||||
private void downloadFile(final RemoteResourceInfo remote, final File local)
|
||||
throws IOException {
|
||||
local = FileTransferUtil.getTargetFile(local, remote.getName());
|
||||
setAttributes(remote, local);
|
||||
RemoteFile rf = sftp.open(remote.getPath());
|
||||
final File adjusted = FileTransferUtil.getTargetFile(local, remote.getName());
|
||||
setAttributes(remote, adjusted);
|
||||
final RemoteFile rf = sftp.open(remote.getPath());
|
||||
try {
|
||||
final FileOutputStream fos = new FileOutputStream(local);
|
||||
final FileOutputStream fos = new FileOutputStream(adjusted);
|
||||
try {
|
||||
StreamCopier.copy(rf.getInputStream(), fos, sftp.getSubsystem()
|
||||
.getLocalMaxPacketSize(), false);
|
||||
@@ -124,119 +113,54 @@ public class SFTPFileTransfer
|
||||
}
|
||||
}
|
||||
|
||||
private void downloadDir(RemoteResourceInfo remote, File local)
|
||||
private void downloadDir(final RemoteResourceInfo remote, final File local)
|
||||
throws IOException {
|
||||
local = FileTransferUtil.getTargetDirectory(local, remote.getName());
|
||||
setAttributes(remote, local);
|
||||
final File adjusted = FileTransferUtil.getTargetDirectory(local, remote.getName());
|
||||
setAttributes(remote, adjusted);
|
||||
final RemoteDirectory rd = sftp.openDir(remote.getPath());
|
||||
for (RemoteResourceInfo rri : rd.scan(filter))
|
||||
download(rri, new File(local.getPath(), rri.getName()));
|
||||
rd.close();
|
||||
try {
|
||||
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
|
||||
download(rri, new File(adjusted.getPath(), rri.getName()));
|
||||
} finally {
|
||||
rd.close();
|
||||
}
|
||||
}
|
||||
|
||||
void download(RemoteResourceInfo remote, File local)
|
||||
void download(final RemoteResourceInfo remote, final File local)
|
||||
throws IOException {
|
||||
log.info("Downloading [{}] to [{}]", remote, local);
|
||||
switch (remote.getAttributes().getType()) {
|
||||
case DIRECTORY:
|
||||
downloadDir(remote, local);
|
||||
break;
|
||||
case UNKNOWN: // ... BS servers like wodFTPD
|
||||
case UNKNOWN:
|
||||
log.warn("Server did not supply information about the type of file at `{}` -- assuming it is a regular file!");
|
||||
case REGULAR:
|
||||
downloadFile(remote, local);
|
||||
break;
|
||||
default:
|
||||
throw new IOException(remote + " is not a regular file or directory");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class Uploader {
|
||||
|
||||
private final ModeGetter modeGetter;
|
||||
private final FileFilter filter;
|
||||
|
||||
Uploader(ModeGetter modeGetter, FileFilter filter) {
|
||||
this.modeGetter = modeGetter;
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
public FileAttributes getAttributes(File local)
|
||||
void upload(File local, String remote)
|
||||
throws IOException {
|
||||
FileAttributes.Builder builder = new FileAttributes.Builder().withPermissions(modeGetter
|
||||
.getPermissions(local));
|
||||
if (modeGetter.preservesTimes())
|
||||
builder.withAtimeMtime(modeGetter.getLastAccessTime(local), modeGetter.getLastModifiedTime(local));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
// tread carefully
|
||||
private void setAttributes(FileAttributes current, File local, String remote)
|
||||
throws IOException {
|
||||
final FileAttributes attrs = getAttributes(local);
|
||||
// TODO whoaaa.. simplify?
|
||||
if (!(current != null
|
||||
&& current.getMode().getPermissionsMask() == attrs.getMode().getPermissionsMask()
|
||||
&& (!modeGetter.preservesTimes()
|
||||
|| (attrs.getAtime() == current.getAtime() && attrs.getMtime() == current.getMtime()))))
|
||||
sftp.setAttributes(remote, attrs);
|
||||
}
|
||||
|
||||
private String prepareDir(File local, String remote)
|
||||
throws IOException {
|
||||
FileAttributes attrs;
|
||||
try {
|
||||
attrs = sftp.stat(remote);
|
||||
} catch (SFTPException e) {
|
||||
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
|
||||
log.debug("probeDir: {} does not exist, creating", remote);
|
||||
sftp.makeDir(remote, getAttributes(local));
|
||||
return remote;
|
||||
} else
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY)
|
||||
if (pathHelper.getComponents(remote).getName().equals(local.getName())) {
|
||||
log.debug("probeDir: {} already exists", remote);
|
||||
setAttributes(attrs, local, remote);
|
||||
return remote;
|
||||
} else {
|
||||
log.debug("probeDir: {} already exists, path adjusted for {}", remote, local.getName());
|
||||
return prepareDir(local, PathComponents.adjustForParent(remote, local.getName()));
|
||||
}
|
||||
log.info("Uploading [{}] to [{}]", local, remote);
|
||||
if (local.isDirectory())
|
||||
uploadDir(local, remote);
|
||||
else if (local.isFile())
|
||||
uploadFile(local, remote);
|
||||
else
|
||||
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
|
||||
}
|
||||
|
||||
private String prepareFile(File local, String remote)
|
||||
throws IOException {
|
||||
FileAttributes attrs;
|
||||
try {
|
||||
attrs = sftp.stat(remote);
|
||||
} catch (SFTPException e) {
|
||||
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
|
||||
log.debug("probeFile: {} does not exist", remote);
|
||||
return remote;
|
||||
} else
|
||||
throw e;
|
||||
}
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY) {
|
||||
log.debug("probeFile: {} was directory, path adjusted for {}", remote, local.getName());
|
||||
remote = PathComponents.adjustForParent(remote, local.getName());
|
||||
return remote;
|
||||
} else {
|
||||
log.debug("probeFile: {} is a {} file that will be replaced", remote, attrs.getMode().getType());
|
||||
return remote;
|
||||
}
|
||||
throw new IOException(local + " is not a file or directory");
|
||||
}
|
||||
|
||||
private void uploadDir(File local, String remote)
|
||||
throws IOException {
|
||||
final String adjusted = prepareDir(local, remote);
|
||||
for (File f : local.listFiles(filter))
|
||||
for (File f : local.listFiles(getUploadFilter()))
|
||||
upload(f, adjusted);
|
||||
}
|
||||
|
||||
@@ -258,16 +182,69 @@ public class SFTPFileTransfer
|
||||
}
|
||||
}
|
||||
|
||||
void upload(File local, String remote)
|
||||
private String prepareDir(File local, String remote)
|
||||
throws IOException {
|
||||
log.info("Uploading [{}] to [{}]", local, remote);
|
||||
if (local.isDirectory())
|
||||
uploadDir(local, remote);
|
||||
else if (local.isFile())
|
||||
uploadFile(local, remote);
|
||||
final FileAttributes attrs;
|
||||
try {
|
||||
attrs = sftp.stat(remote);
|
||||
} catch (SFTPException e) {
|
||||
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
|
||||
log.debug("probeDir: {} does not exist, creating", remote);
|
||||
sftp.makeDir(remote, getAttributes(local));
|
||||
return remote;
|
||||
} else
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY)
|
||||
if (pathHelper.getComponents(remote).getName().equals(local.getName())) {
|
||||
log.debug("probeDir: {} already exists", remote);
|
||||
final FileAttributes localAttrs = getAttributes(local);
|
||||
if (attrs.getMode().getMask() != localAttrs.getMode().getMask()
|
||||
|| (getModeGetter().preservesTimes()
|
||||
&& (attrs.getAtime() != attrs.getAtime() || attrs.getMtime() != localAttrs.getMtime())))
|
||||
sftp.setAttributes(remote, localAttrs);
|
||||
return remote;
|
||||
} else {
|
||||
log.debug("probeDir: {} already exists, path adjusted for {}", remote, local.getName());
|
||||
return prepareDir(local, PathComponents.adjustForParent(remote, local.getName()));
|
||||
}
|
||||
else
|
||||
throw new IOException(local + " is not a file or directory");
|
||||
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
|
||||
}
|
||||
|
||||
private String prepareFile(File local, String remote)
|
||||
throws IOException {
|
||||
final FileAttributes attrs;
|
||||
try {
|
||||
attrs = sftp.stat(remote);
|
||||
} catch (SFTPException e) {
|
||||
if (e.getStatusCode() == StatusCode.NO_SUCH_FILE) {
|
||||
log.debug("probeFile: {} does not exist", remote);
|
||||
return remote;
|
||||
} else
|
||||
throw e;
|
||||
}
|
||||
if (attrs.getMode().getType() == FileMode.Type.DIRECTORY) {
|
||||
log.debug("probeFile: {} was directory, path adjusted for {}", remote, local.getName());
|
||||
remote = PathComponents.adjustForParent(remote, local.getName());
|
||||
return remote;
|
||||
} else {
|
||||
log.debug("probeFile: {} is a {} file that will be replaced", remote, attrs.getMode().getType());
|
||||
return remote;
|
||||
}
|
||||
}
|
||||
|
||||
private FileAttributes getAttributes(File local)
|
||||
throws IOException {
|
||||
final FileAttributes.Builder builder = new FileAttributes.Builder()
|
||||
.withType(local.isDirectory() ? FileMode.Type.DIRECTORY : FileMode.Type.REGULAR)
|
||||
.withPermissions(getModeGetter().getPermissions(local));
|
||||
if (getModeGetter().preservesTimes())
|
||||
builder.withAtimeMtime(getModeGetter().getLastAccessTime(local), getModeGetter().getLastModifiedTime(local));
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user