mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-08 00:00:54 +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) {
|
public Builder withPermissions(Set<FilePermission> perms) {
|
||||||
mask |= Flag.MODE.get();
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder withPermissions(int perms) {
|
public Builder withPermissions(int perms) {
|
||||||
mask |= Flag.MODE.get();
|
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;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -208,7 +214,7 @@ public final class FileAttributes {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
StringBuilder sb = new StringBuilder("[");
|
final StringBuilder sb = new StringBuilder("[");
|
||||||
|
|
||||||
if (has(Flag.SIZE))
|
if (has(Flag.SIZE))
|
||||||
sb.append("size=").append(size).append(";");
|
sb.append("size=").append(size).append(";");
|
||||||
|
|||||||
@@ -53,8 +53,8 @@ public class FileMode {
|
|||||||
return UNKNOWN;
|
return UNKNOWN;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static int toMask(Type t) {
|
public int toMask() {
|
||||||
return t.val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,8 +20,6 @@ import net.schmizz.sshj.sftp.Response.StatusCode;
|
|||||||
import net.schmizz.sshj.xfer.AbstractFileTransfer;
|
import net.schmizz.sshj.xfer.AbstractFileTransfer;
|
||||||
import net.schmizz.sshj.xfer.FileTransfer;
|
import net.schmizz.sshj.xfer.FileTransfer;
|
||||||
import net.schmizz.sshj.xfer.FileTransferUtil;
|
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.File;
|
||||||
import java.io.FileFilter;
|
import java.io.FileFilter;
|
||||||
@@ -59,15 +57,14 @@ public class SFTPFileTransfer
|
|||||||
|
|
||||||
public void upload(String source, String dest)
|
public void upload(String source, String dest)
|
||||||
throws IOException {
|
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)
|
public void download(String source, String dest)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final PathComponents pathComponents = pathHelper.getComponents(source);
|
final PathComponents pathComponents = pathHelper.getComponents(source);
|
||||||
final FileAttributes attributes = sftp.stat(source);
|
final FileAttributes attributes = sftp.stat(source);
|
||||||
new Downloader(getModeSetter(), getDownloadFilter())
|
new Downloader().download(new RemoteResourceInfo(pathComponents, attributes), new File(dest));
|
||||||
.download(new RemoteResourceInfo(pathComponents, attributes), new File(dest));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setUploadFilter(FileFilter uploadFilter) {
|
public void setUploadFilter(FileFilter uploadFilter) {
|
||||||
@@ -88,31 +85,23 @@ public class SFTPFileTransfer
|
|||||||
|
|
||||||
private class Downloader {
|
private class Downloader {
|
||||||
|
|
||||||
private final ModeSetter modeSetter;
|
private void setAttributes(final RemoteResourceInfo remote, final File local)
|
||||||
private final RemoteResourceFilter filter;
|
|
||||||
|
|
||||||
Downloader(ModeSetter modeSetter, RemoteResourceFilter filter) {
|
|
||||||
this.modeSetter = modeSetter;
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setAttributes(RemoteResourceInfo remote, File local)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final FileAttributes attrs = remote.getAttributes();
|
final FileAttributes attrs = remote.getAttributes();
|
||||||
modeSetter.setPermissions(local, attrs.getMode().getPermissionsMask());
|
getModeSetter().setPermissions(local, attrs.getMode().getPermissionsMask());
|
||||||
if (modeSetter.preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) {
|
if (getModeSetter().preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) {
|
||||||
modeSetter.setLastAccessedTime(local, attrs.getAtime());
|
getModeSetter().setLastAccessedTime(local, attrs.getAtime());
|
||||||
modeSetter.setLastModifiedTime(local, attrs.getMtime());
|
getModeSetter().setLastModifiedTime(local, attrs.getMtime());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void downloadFile(RemoteResourceInfo remote, File local)
|
private void downloadFile(final RemoteResourceInfo remote, final File local)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
local = FileTransferUtil.getTargetFile(local, remote.getName());
|
final File adjusted = FileTransferUtil.getTargetFile(local, remote.getName());
|
||||||
setAttributes(remote, local);
|
setAttributes(remote, adjusted);
|
||||||
RemoteFile rf = sftp.open(remote.getPath());
|
final RemoteFile rf = sftp.open(remote.getPath());
|
||||||
try {
|
try {
|
||||||
final FileOutputStream fos = new FileOutputStream(local);
|
final FileOutputStream fos = new FileOutputStream(adjusted);
|
||||||
try {
|
try {
|
||||||
StreamCopier.copy(rf.getInputStream(), fos, sftp.getSubsystem()
|
StreamCopier.copy(rf.getInputStream(), fos, sftp.getSubsystem()
|
||||||
.getLocalMaxPacketSize(), false);
|
.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 {
|
throws IOException {
|
||||||
local = FileTransferUtil.getTargetDirectory(local, remote.getName());
|
final File adjusted = FileTransferUtil.getTargetDirectory(local, remote.getName());
|
||||||
setAttributes(remote, local);
|
setAttributes(remote, adjusted);
|
||||||
final RemoteDirectory rd = sftp.openDir(remote.getPath());
|
final RemoteDirectory rd = sftp.openDir(remote.getPath());
|
||||||
for (RemoteResourceInfo rri : rd.scan(filter))
|
try {
|
||||||
download(rri, new File(local.getPath(), rri.getName()));
|
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
|
||||||
rd.close();
|
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 {
|
throws IOException {
|
||||||
log.info("Downloading [{}] to [{}]", remote, local);
|
log.info("Downloading [{}] to [{}]", remote, local);
|
||||||
switch (remote.getAttributes().getType()) {
|
switch (remote.getAttributes().getType()) {
|
||||||
case DIRECTORY:
|
case DIRECTORY:
|
||||||
downloadDir(remote, local);
|
downloadDir(remote, local);
|
||||||
break;
|
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!");
|
log.warn("Server did not supply information about the type of file at `{}` -- assuming it is a regular file!");
|
||||||
case REGULAR:
|
case REGULAR:
|
||||||
downloadFile(remote, local);
|
downloadFile(remote, local);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
throw new IOException(remote + " is not a regular file or directory");
|
throw new IOException(remote + " is not a regular file or directory");
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Uploader {
|
private class Uploader {
|
||||||
|
|
||||||
private final ModeGetter modeGetter;
|
void upload(File local, String remote)
|
||||||
private final FileFilter filter;
|
|
||||||
|
|
||||||
Uploader(ModeGetter modeGetter, FileFilter filter) {
|
|
||||||
this.modeGetter = modeGetter;
|
|
||||||
this.filter = filter;
|
|
||||||
}
|
|
||||||
|
|
||||||
public FileAttributes getAttributes(File local)
|
|
||||||
throws IOException {
|
throws IOException {
|
||||||
FileAttributes.Builder builder = new FileAttributes.Builder().withPermissions(modeGetter
|
log.info("Uploading [{}] to [{}]", local, remote);
|
||||||
.getPermissions(local));
|
if (local.isDirectory())
|
||||||
if (modeGetter.preservesTimes())
|
uploadDir(local, remote);
|
||||||
builder.withAtimeMtime(modeGetter.getLastAccessTime(local), modeGetter.getLastModifiedTime(local));
|
else if (local.isFile())
|
||||||
return builder.build();
|
uploadFile(local, remote);
|
||||||
}
|
|
||||||
|
|
||||||
// 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()));
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
|
throw new IOException(local + " is not a file or directory");
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void uploadDir(File local, String remote)
|
private void uploadDir(File local, String remote)
|
||||||
throws IOException {
|
throws IOException {
|
||||||
final String adjusted = prepareDir(local, remote);
|
final String adjusted = prepareDir(local, remote);
|
||||||
for (File f : local.listFiles(filter))
|
for (File f : local.listFiles(getUploadFilter()))
|
||||||
upload(f, adjusted);
|
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 {
|
throws IOException {
|
||||||
log.info("Uploading [{}] to [{}]", local, remote);
|
final FileAttributes attrs;
|
||||||
if (local.isDirectory())
|
try {
|
||||||
uploadDir(local, remote);
|
attrs = sftp.stat(remote);
|
||||||
else if (local.isFile())
|
} catch (SFTPException e) {
|
||||||
uploadFile(local, remote);
|
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
|
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