* sftp / include file type information when uploading

* misc. sftp cleanups
This commit is contained in:
Shikhar Bhushan
2010-03-12 17:45:37 +01:00
parent 24f6303ca1
commit bb9193b333
3 changed files with 102 additions and 119 deletions

View File

@@ -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(";");

View File

@@ -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;
} }
} }

View File

@@ -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();
}
} }
} }