Lighter, more coherent interfaces by refactoring LocalFile into LocalSourceFile & LocalDestFile

This commit is contained in:
Shikhar Bhushan
2011-04-06 23:37:55 +01:00
parent a2c82de260
commit ce930c969b
13 changed files with 180 additions and 316 deletions

View File

@@ -16,7 +16,8 @@
package net.schmizz.sshj.sftp; package net.schmizz.sshj.sftp;
import net.schmizz.sshj.xfer.FilePermission; import net.schmizz.sshj.xfer.FilePermission;
import net.schmizz.sshj.xfer.LocalFile; import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.LocalSourceFile;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
@@ -239,12 +240,12 @@ public class SFTPClient
xfer.upload(source, dest); xfer.upload(source, dest);
} }
public void get(String source, LocalFile dest) public void get(String source, LocalDestFile dest)
throws IOException { throws IOException {
xfer.download(source, dest); xfer.download(source, dest);
} }
public void put(LocalFile source, String dest) public void put(LocalSourceFile source, String dest)
throws IOException { throws IOException {
xfer.upload(source, dest); xfer.upload(source, dest);
} }

View File

@@ -20,8 +20,9 @@ import net.schmizz.sshj.sftp.Response.StatusCode;
import net.schmizz.sshj.xfer.AbstractFileTransfer; import net.schmizz.sshj.xfer.AbstractFileTransfer;
import net.schmizz.sshj.xfer.FileSystemFile; import net.schmizz.sshj.xfer.FileSystemFile;
import net.schmizz.sshj.xfer.FileTransfer; import net.schmizz.sshj.xfer.FileTransfer;
import net.schmizz.sshj.xfer.LocalFile; import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.LocalFileFilter; import net.schmizz.sshj.xfer.LocalFileFilter;
import net.schmizz.sshj.xfer.LocalSourceFile;
import net.schmizz.sshj.xfer.TransferListener; import net.schmizz.sshj.xfer.TransferListener;
import java.io.IOException; import java.io.IOException;
@@ -57,13 +58,13 @@ public class SFTPFileTransfer
} }
@Override @Override
public void upload(LocalFile localFile, String remotePath) public void upload(LocalSourceFile localFile, String remotePath)
throws IOException { throws IOException {
new Uploader().upload(localFile, remotePath); new Uploader().upload(localFile, remotePath);
} }
@Override @Override
public void download(String source, LocalFile dest) public void download(String source, LocalDestFile dest)
throws IOException { throws IOException {
final PathComponents pathComponents = pathHelper.getComponents(source); final PathComponents pathComponents = pathHelper.getComponents(source);
final FileAttributes attributes = engine.stat(source); final FileAttributes attributes = engine.stat(source);
@@ -90,9 +91,9 @@ public class SFTPFileTransfer
private final TransferListener listener = getTransferListener(); private final TransferListener listener = getTransferListener();
private void download(final RemoteResourceInfo remote, final LocalFile local) private void download(final RemoteResourceInfo remote, final LocalDestFile local)
throws IOException { throws IOException {
final LocalFile adjustedFile; final LocalDestFile adjustedFile;
switch (remote.getAttributes().getType()) { switch (remote.getAttributes().getType()) {
case DIRECTORY: case DIRECTORY:
listener.startedDir(remote.getName()); listener.startedDir(remote.getName());
@@ -114,9 +115,9 @@ public class SFTPFileTransfer
} }
private LocalFile downloadDir(final RemoteResourceInfo remote, final LocalFile local) private LocalDestFile downloadDir(final RemoteResourceInfo remote, final LocalDestFile local)
throws IOException { throws IOException {
final LocalFile adjusted = local.getTargetDirectory(remote.getName()); final LocalDestFile adjusted = local.getTargetDirectory(remote.getName());
final RemoteDirectory rd = engine.openDir(remote.getPath()); final RemoteDirectory rd = engine.openDir(remote.getPath());
try { try {
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter())) for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
@@ -127,9 +128,9 @@ public class SFTPFileTransfer
return adjusted; return adjusted;
} }
private LocalFile downloadFile(final RemoteResourceInfo remote, final LocalFile local) private LocalDestFile downloadFile(final RemoteResourceInfo remote, final LocalDestFile local)
throws IOException { throws IOException {
final LocalFile adjusted = local.getTargetFile(remote.getName()); final LocalDestFile adjusted = local.getTargetFile(remote.getName());
final RemoteFile rf = engine.open(remote.getPath()); final RemoteFile rf = engine.open(remote.getPath());
try { try {
final OutputStream os = adjusted.getOutputStream(); final OutputStream os = adjusted.getOutputStream();
@@ -145,11 +146,11 @@ public class SFTPFileTransfer
return adjusted; return adjusted;
} }
private void copyAttributes(final RemoteResourceInfo remote, final LocalFile local) private void copyAttributes(final RemoteResourceInfo remote, final LocalDestFile local)
throws IOException { throws IOException {
final FileAttributes attrs = remote.getAttributes(); final FileAttributes attrs = remote.getAttributes();
local.setPermissions(attrs.getMode().getPermissionsMask()); local.setPermissions(attrs.getMode().getPermissionsMask());
if (local.preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) { if (attrs.has(FileAttributes.Flag.ACMODTIME)) {
local.setLastAccessedTime(attrs.getAtime()); local.setLastAccessedTime(attrs.getAtime());
local.setLastModifiedTime(attrs.getMtime()); local.setLastModifiedTime(attrs.getMtime());
} }
@@ -161,7 +162,7 @@ public class SFTPFileTransfer
private final TransferListener listener = getTransferListener(); private final TransferListener listener = getTransferListener();
private void upload(LocalFile local, String remote) private void upload(LocalSourceFile local, String remote)
throws IOException { throws IOException {
final String adjustedPath; final String adjustedPath;
if (local.isDirectory()) { if (local.isDirectory()) {
@@ -169,7 +170,7 @@ public class SFTPFileTransfer
adjustedPath = uploadDir(local, remote); adjustedPath = uploadDir(local, remote);
listener.finishedDir(); listener.finishedDir();
} else if (local.isFile()) { } else if (local.isFile()) {
listener.startedFile(local.getName(), local.length()); listener.startedFile(local.getName(), local.getLength());
adjustedPath = uploadFile(local, remote); adjustedPath = uploadFile(local, remote);
listener.finishedFile(); listener.finishedFile();
} else } else
@@ -177,15 +178,15 @@ public class SFTPFileTransfer
engine.setAttributes(adjustedPath, getAttributes(local)); engine.setAttributes(adjustedPath, getAttributes(local));
} }
private String uploadDir(LocalFile local, String remote) private String uploadDir(LocalSourceFile local, String remote)
throws IOException { throws IOException {
final String adjusted = prepareDir(local, remote); final String adjusted = prepareDir(local, remote);
for (LocalFile f : local.getChildren(getUploadFilter())) for (LocalSourceFile f : local.getChildren(getUploadFilter()))
upload(f, adjusted); upload(f, adjusted);
return adjusted; return adjusted;
} }
private String uploadFile(LocalFile local, String remote) private String uploadFile(LocalSourceFile local, String remote)
throws IOException { throws IOException {
final String adjusted = prepareFile(local, remote); final String adjusted = prepareFile(local, remote);
final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE, final RemoteFile rf = engine.open(adjusted, EnumSet.of(OpenMode.WRITE,
@@ -205,7 +206,7 @@ public class SFTPFileTransfer
return adjusted; return adjusted;
} }
private String prepareDir(LocalFile local, String remote) private String prepareDir(LocalSourceFile local, String remote)
throws IOException { throws IOException {
final FileAttributes attrs; final FileAttributes attrs;
try { try {
@@ -231,7 +232,7 @@ public class SFTPFileTransfer
throw new IOException(attrs.getMode().getType() + " file already exists at " + remote); throw new IOException(attrs.getMode().getType() + " file already exists at " + remote);
} }
private String prepareFile(LocalFile local, String remote) private String prepareFile(LocalSourceFile local, String remote)
throws IOException { throws IOException {
final FileAttributes attrs; final FileAttributes attrs;
try { try {
@@ -253,10 +254,10 @@ public class SFTPFileTransfer
} }
} }
private FileAttributes getAttributes(LocalFile local) private FileAttributes getAttributes(LocalSourceFile local)
throws IOException { throws IOException {
final FileAttributes.Builder builder = new FileAttributes.Builder().withPermissions(local.getPermissions()); final FileAttributes.Builder builder = new FileAttributes.Builder().withPermissions(local.getPermissions());
if (local.preservesTimes()) if (local.providesAtimeMtime())
builder.withAtimeMtime(local.getLastAccessTime(), local.getLastModifiedTime()); builder.withAtimeMtime(local.getLastAccessTime(), local.getLastModifiedTime());
return builder.build(); return builder.build();
} }

View File

@@ -31,7 +31,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
public class FileSystemFile public class FileSystemFile
implements LocalFile { implements LocalSourceFile, LocalDestFile {
protected final Logger log = LoggerFactory.getLogger(getClass()); protected final Logger log = LoggerFactory.getLogger(getClass());
@@ -65,7 +65,7 @@ public class FileSystemFile
} }
@Override @Override
public long length() { public long getLength() {
return file.length(); return file.length();
} }
@@ -81,12 +81,6 @@ public class FileSystemFile
return new FileOutputStream(file); return new FileOutputStream(file);
} }
@Override
public Iterable<FileSystemFile> getChildren()
throws IOException {
return getChildren(null);
}
@Override @Override
public Iterable<FileSystemFile> getChildren(final LocalFileFilter filter) public Iterable<FileSystemFile> getChildren(final LocalFileFilter filter)
throws IOException { throws IOException {
@@ -111,6 +105,11 @@ public class FileSystemFile
return children; return children;
} }
@Override
public boolean providesAtimeMtime() {
return true;
}
@Override @Override
public long getLastAccessTime() public long getLastAccessTime()
throws IOException { throws IOException {
@@ -160,11 +159,6 @@ public class FileSystemFile
log.warn("Could not set permissions for {} to {}", file, Integer.toString(perms, 16)); log.warn("Could not set permissions for {} to {}", file, Integer.toString(perms, 16));
} }
@Override
public boolean preservesTimes() {
return true;
}
@Override @Override
public FileSystemFile getChild(String name) { public FileSystemFile getChild(String name) {
return new FileSystemFile(new File(file, name)); return new FileSystemFile(new File(file, name));

View File

@@ -25,10 +25,10 @@ public interface FileTransfer {
void download(String remotePath, String localPath) void download(String remotePath, String localPath)
throws IOException; throws IOException;
void upload(LocalFile localFile, String remotePath) void upload(LocalSourceFile localFile, String remotePath)
throws IOException; throws IOException;
void download(String remotePath, LocalFile localFile) void download(String remotePath, LocalDestFile localFile)
throws IOException; throws IOException;
TransferListener getTransferListener(); TransferListener getTransferListener();

View File

@@ -19,123 +19,45 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class InMemoryDestFile public abstract class InMemoryDestFile
implements LocalFile { implements LocalDestFile {
protected final Logger log = LoggerFactory.getLogger(getClass()); protected final Logger log = LoggerFactory.getLogger(getClass());
protected final String filename;
protected final OutputStream outStream;
public InMemoryDestFile(String filename, OutputStream outStream) {
this.filename = filename;
this.outStream = outStream;
}
@Override @Override
public String getName() { public InMemoryDestFile getTargetFile(String filename)
return filename;
}
@Override
public LocalFile getTargetFile(String filename)
throws IOException { throws IOException {
if (filename.equals(this.filename))
return this; return this;
else
throw new IOException("Filename mismatch");
}
@Override
public boolean isFile() {
return true;
}
@Override
public boolean isDirectory() {
return false;
}
@Override
public OutputStream getOutputStream()
throws IOException {
return outStream;
}
// Everything else is unimplemented
@Override
public long length() {
return 0;
}
@Override
public InputStream getInputStream()
throws IOException {
return null;
}
@Override
public Iterable<LocalFile> getChildren()
throws IOException {
return null;
}
@Override
public Iterable<LocalFile> getChildren(LocalFileFilter filter)
throws IOException {
return null;
}
@Override
public long getLastAccessTime()
throws IOException {
return 0;
}
@Override
public long getLastModifiedTime()
throws IOException {
return 0;
}
@Override
public int getPermissions()
throws IOException {
return 0;
} }
@Override @Override
public void setLastAccessedTime(long t) public void setLastAccessedTime(long t)
throws IOException { throws IOException {
log.info("atime = {}", t);
} }
@Override @Override
public void setLastModifiedTime(long t) public void setLastModifiedTime(long t)
throws IOException { throws IOException {
log.info("mtime = {}", t);
} }
@Override @Override
public void setPermissions(int perms) public void setPermissions(int perms)
throws IOException { throws IOException {
log.info("permissions = {}", Integer.toOctalString(perms));
} }
@Override @Override
public boolean preservesTimes() { public LocalDestFile getTargetDirectory(String dirname)
return false; throws IOException {
throw new AssertionError("Unimplemented");
} }
@Override @Override
public LocalFile getChild(String name) { public LocalDestFile getChild(String name) {
return null; throw new AssertionError("Unimplemented");
}
@Override
public LocalFile getTargetDirectory(String dirname) {
return null;
} }
} }

View File

@@ -19,38 +19,12 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class InMemorySourceFile public abstract class InMemorySourceFile
implements LocalFile { implements LocalSourceFile {
protected final Logger log = LoggerFactory.getLogger(getClass()); protected final Logger log = LoggerFactory.getLogger(getClass());
protected final String filename;
protected final long length;
protected final InputStream inStream;
public InMemorySourceFile(String filename, long length, InputStream inStream) {
this.filename = filename;
this.length = length;
this.inStream = inStream;
}
@Override
public String getName() {
return filename;
}
@Override
public LocalFile getTargetFile(String filename)
throws IOException {
if (filename.equals(this.filename))
return this;
else
throw new IOException("Filename mismatch");
}
@Override @Override
public boolean isFile() { public boolean isFile() {
return true; return true;
@@ -61,83 +35,33 @@ public class InMemorySourceFile
return false; return false;
} }
@Override
public long length() {
return length;
}
@Override
public InputStream getInputStream()
throws IOException {
return inStream;
}
@Override @Override
public int getPermissions() public int getPermissions()
throws IOException { throws IOException {
return 0644; return 0644;
} }
// Everything else is unimplemented
@Override @Override
public OutputStream getOutputStream() public boolean providesAtimeMtime() {
throws IOException { return false;
return null;
}
@Override
public Iterable<LocalFile> getChildren()
throws IOException {
return null;
}
@Override
public Iterable<LocalFile> getChildren(LocalFileFilter filter)
throws IOException {
return null;
} }
@Override @Override
public long getLastAccessTime() public long getLastAccessTime()
throws IOException { throws IOException {
return 0; throw new AssertionError("Unimplemented");
} }
@Override @Override
public long getLastModifiedTime() public long getLastModifiedTime()
throws IOException { throws IOException {
return 0; throw new AssertionError("Unimplemented");
} }
@Override @Override
public void setLastAccessedTime(long t) public Iterable<? extends LocalSourceFile> getChildren(LocalFileFilter filter)
throws IOException { throws IOException {
} throw new AssertionError("Unimplemented");
@Override
public void setLastModifiedTime(long t)
throws IOException {
}
@Override
public void setPermissions(int perms)
throws IOException {
}
@Override
public boolean preservesTimes() {
return false;
}
@Override
public LocalFile getChild(String name) {
return null;
}
@Override
public LocalFile getTargetDirectory(String dirname) {
return null;
} }
} }

View File

@@ -16,57 +16,41 @@
package net.schmizz.sshj.xfer; package net.schmizz.sshj.xfer;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream; import java.io.OutputStream;
// TODO Document all methods properly public interface LocalDestFile {
public interface LocalFile { OutputStream getOutputStream()
throws IOException;
String getName(); /** @return A child file/directory of this directory with given {@code name}. */
LocalDestFile getChild(String name);
boolean isFile();
boolean isDirectory();
long length();
InputStream getInputStream() throws IOException;
OutputStream getOutputStream() throws IOException;
Iterable<? extends LocalFile> getChildren() throws IOException;
Iterable<? extends LocalFile> getChildren(LocalFileFilter filter) throws IOException;
/** /**
* Returns last access time for the underlying file. * Allows caller to express intent that caller expects to write to file with {@code filename}. Based on this
* * information, an implementation may return an alternate file to write to, which should be respected by the
* @return time in seconds since Unix epoch * caller.
*
* @throws IOException
*/ */
long getLastAccessTime() LocalDestFile getTargetFile(String filename)
throws IOException; throws IOException;
/** /**
* Returns last access time for the underlying file. * Allows caller to express intent that caller expects to write to directory with {@code dirname}. Based on this
* * information, an implementation may return an alternate directory to write to, which should be respected by the
* @return time in seconds since Unix epoch * caller.
*
* @throws IOException
*/ */
long getLastModifiedTime() LocalDestFile getTargetDirectory(String dirname)
throws IOException; throws IOException;
/** /**
* Returns the permissions for the underlying file * Set the permissions for the underlying file.
* *
* @return permissions in octal format, e.g. 0644 * @param f the file
* @param perms permissions e.g. 0644
* *
* @throws IOException * @throws IOException
*/ */
int getPermissions() void setPermissions(int perms)
throws IOException; throws IOException;
/** /**
@@ -90,25 +74,4 @@ public interface LocalFile {
void setLastModifiedTime(long t) void setLastModifiedTime(long t)
throws IOException; throws IOException;
/**
* Set the permissions for the underlying file.
*
* @param f the file
* @param perms permissions in octal format, e.g. 0644
*
* @throws IOException
*/
void setPermissions(int perms)
throws IOException;
/** @return whether this implementation is interested in preserving mtime and atime. */
boolean preservesTimes();
/** @return A child file of this directory having {@code name} as filename */
LocalFile getChild(String name);
LocalFile getTargetFile(String filename) throws IOException;
LocalFile getTargetDirectory(String dirname) throws IOException;
} }

View File

@@ -17,6 +17,6 @@ package net.schmizz.sshj.xfer;
public interface LocalFileFilter { public interface LocalFileFilter {
boolean accept(LocalFile file); boolean accept(LocalSourceFile file);
} }

View File

@@ -0,0 +1,68 @@
/*
* Copyright 2011 sshj contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package net.schmizz.sshj.xfer;
import java.io.IOException;
import java.io.InputStream;
public interface LocalSourceFile {
String getName();
long getLength();
InputStream getInputStream()
throws IOException;
/**
* Returns the permissions for the underlying file
*
* @return permissions e.g. 0644
*
* @throws IOException
*/
int getPermissions() throws IOException;
boolean isFile();
boolean isDirectory();
Iterable<? extends LocalSourceFile> getChildren(LocalFileFilter filter)
throws IOException;
boolean providesAtimeMtime();
/**
* Returns last access time for the underlying file.
*
* @return time in seconds since Unix epoch
*
* @throws IOException
*/
long getLastAccessTime()
throws IOException;
/**
* Returns last access time for the underlying file.
*
* @return time in seconds since Unix epoch
*
* @throws IOException
*/
long getLastModifiedTime()
throws IOException;
}

View File

@@ -21,7 +21,7 @@ import java.util.LinkedList;
import java.util.List; import java.util.List;
import net.schmizz.sshj.common.IOUtils; import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.xfer.LocalFile; import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg; import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;
/** Support for uploading files over a connected link using SCP. */ /** Support for uploading files over a connected link using SCP. */
@@ -36,7 +36,7 @@ public final class SCPDownloadClient {
} }
/** Download a file from {@code sourcePath} on the connected host to {@code targetPath} locally. */ /** Download a file from {@code sourcePath} on the connected host to {@code targetPath} locally. */
public synchronized int copy(String sourcePath, LocalFile targetFile) public synchronized int copy(String sourcePath, LocalDestFile targetFile)
throws IOException { throws IOException {
engine.cleanSlate(); engine.cleanSlate();
try { try {
@@ -55,15 +55,14 @@ public final class SCPDownloadClient {
this.recursive = recursive; this.recursive = recursive;
} }
void startCopy(String sourcePath, LocalFile targetFile) void startCopy(String sourcePath, LocalDestFile targetFile)
throws IOException { throws IOException {
List<Arg> args = new LinkedList<Arg>(); List<Arg> args = new LinkedList<Arg>();
args.add(Arg.SOURCE); args.add(Arg.SOURCE);
args.add(Arg.QUIET); args.add(Arg.QUIET);
args.add(Arg.PRESERVE_TIMES);
if (recursive) if (recursive)
args.add(Arg.RECURSIVE); args.add(Arg.RECURSIVE);
if (targetFile.preservesTimes())
args.add(Arg.PRESERVE_TIMES);
engine.execSCPWith(args, sourcePath); engine.execSCPWith(args, sourcePath);
engine.signal("Start status OK"); engine.signal("Start status OK");
@@ -92,7 +91,7 @@ public final class SCPDownloadClient {
return Integer.parseInt(cmd.substring(1), 8); return Integer.parseInt(cmd.substring(1), 8);
} }
private boolean process(String bufferedTMsg, String msg, LocalFile f) private boolean process(String bufferedTMsg, String msg, LocalDestFile f)
throws IOException { throws IOException {
if (msg.length() < 1) if (msg.length() < 1)
throw new SCPException("Could not parse message `" + msg + "`"); throw new SCPException("Could not parse message `" + msg + "`");
@@ -128,7 +127,7 @@ public final class SCPDownloadClient {
return false; return false;
} }
private void processDirectory(String dMsg, String tMsg, LocalFile f) private void processDirectory(String dMsg, String tMsg, LocalDestFile f)
throws IOException { throws IOException {
final String[] dMsgParts = tokenize(dMsg, 3); // D<perms> 0 <dirname> final String[] dMsgParts = tokenize(dMsg, 3); // D<perms> 0 <dirname>
final long length = parseLong(dMsgParts[1], "dir length"); final long length = parseLong(dMsgParts[1], "dir length");
@@ -147,20 +146,20 @@ public final class SCPDownloadClient {
engine.finishedDir(); engine.finishedDir();
} }
private void processFile(String cMsg, String tMsg, LocalFile f) private void processFile(String cMsg, String tMsg, LocalDestFile f)
throws IOException { throws IOException {
final String[] cMsgParts = tokenize(cMsg, 3); // C<perms> <size> <filename> final String[] cMsgParts = tokenize(cMsg, 3); // C<perms> <size> <filename>
final long length = parseLong(cMsgParts[1], "length"); final long length = parseLong(cMsgParts[1], "length");
final String filename = cMsgParts[2]; final String filename = cMsgParts[2];
engine.startedFile(length, filename); engine.startedFile(filename, length);
{ {
f = f.getTargetFile(filename); f = f.getTargetFile(filename);
engine.signal("Remote can start transfer"); engine.signal("Remote can start transfer");
final OutputStream os = f.getOutputStream(); final OutputStream dest = f.getOutputStream();
try { try {
engine.transferFromRemote(length, os); engine.transferFromRemote(dest, length);
} finally { } finally {
IOUtils.closeQuietly(os); IOUtils.closeQuietly(dest);
} }
engine.check("Remote agrees transfer done"); engine.check("Remote agrees transfer done");
setAttributes(f, parsePermissions(cMsgParts[0]), tMsg); setAttributes(f, parsePermissions(cMsgParts[0]), tMsg);
@@ -169,10 +168,10 @@ public final class SCPDownloadClient {
engine.finishedFile(); engine.finishedFile();
} }
private void setAttributes(LocalFile f, int perms, String tMsg) private void setAttributes(LocalDestFile f, int perms, String tMsg)
throws IOException { throws IOException {
f.setPermissions(perms); f.setPermissions(perms);
if (tMsg != null && f.preservesTimes()) { if (tMsg != null) {
String[] tMsgParts = tokenize(tMsg, 4); // e.g. T<mtime> 0 <atime> 0 String[] tMsgParts = tokenize(tMsg, 4); // e.g. T<mtime> 0 <atime> 0
f.setLastModifiedTime(parseLong(tMsgParts[0].substring(1), "last modified time")); f.setLastModifiedTime(parseLong(tMsgParts[0].substring(1), "last modified time"));
f.setLastAccessedTime(parseLong(tMsgParts[2], "last access time")); f.setLastAccessedTime(parseLong(tMsgParts[2], "last access time"));

View File

@@ -24,7 +24,6 @@ import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.common.SSHException; import net.schmizz.sshj.common.SSHException;
import net.schmizz.sshj.connection.channel.direct.Session.Command; import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.connection.channel.direct.SessionFactory; import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import net.schmizz.sshj.xfer.LocalFile;
import net.schmizz.sshj.xfer.TransferListener; import net.schmizz.sshj.xfer.TransferListener;
import org.slf4j.Logger; import org.slf4j.Logger;
@@ -161,14 +160,14 @@ class SCPEngine {
scp.getOutputStream().flush(); scp.getOutputStream().flush();
} }
void transferToRemote(LocalFile f, final InputStream src) void transferToRemote(final InputStream src, final long length)
throws IOException { throws IOException {
transfer(src, scp.getOutputStream(), scp.getRemoteMaxPacketSize(), f.length()); transfer(src, scp.getOutputStream(), scp.getRemoteMaxPacketSize(), length);
} }
void transferFromRemote(final long length, final OutputStream os) void transferFromRemote(final OutputStream dest, final long length)
throws IOException { throws IOException {
transfer(scp.getInputStream(), os, scp.getLocalMaxPacketSize(), length); transfer(scp.getInputStream(), dest, scp.getLocalMaxPacketSize(), length);
} }
private void transfer(InputStream in, OutputStream out, int bufSize, long len) private void transfer(InputStream in, OutputStream out, int bufSize, long len)
@@ -198,22 +197,14 @@ class SCPEngine {
listener.startedDir(dirname); listener.startedDir(dirname);
} }
void startedDir(LocalFile f) {
listener.startedDir(f.getName());
}
void finishedDir() { void finishedDir() {
listener.finishedDir(); listener.finishedDir();
} }
void startedFile(final long length, final String filename) { void startedFile(final String filename, final long length) {
listener.startedFile(filename, length); listener.startedFile(filename, length);
} }
void startedFile(LocalFile f) {
listener.startedFile(f.getName(), f.length());
}
void finishedFile() { void finishedFile() {
listener.finishedFile(); listener.finishedFile();
} }

View File

@@ -21,7 +21,8 @@ import net.schmizz.sshj.connection.channel.direct.SessionFactory;
import net.schmizz.sshj.xfer.AbstractFileTransfer; import net.schmizz.sshj.xfer.AbstractFileTransfer;
import net.schmizz.sshj.xfer.FileSystemFile; import net.schmizz.sshj.xfer.FileSystemFile;
import net.schmizz.sshj.xfer.FileTransfer; import net.schmizz.sshj.xfer.FileTransfer;
import net.schmizz.sshj.xfer.LocalFile; import net.schmizz.sshj.xfer.LocalDestFile;
import net.schmizz.sshj.xfer.LocalSourceFile;
public class SCPFileTransfer public class SCPFileTransfer
extends AbstractFileTransfer extends AbstractFileTransfer
@@ -58,13 +59,13 @@ public class SCPFileTransfer
} }
@Override @Override
public void download(String remotePath, LocalFile localFile) public void download(String remotePath, LocalDestFile localFile)
throws IOException { throws IOException {
newSCPDownloadClient().copy(remotePath, localFile); newSCPDownloadClient().copy(remotePath, localFile);
} }
@Override @Override
public void upload(LocalFile localFile, String remotePath) public void upload(LocalSourceFile localFile, String remotePath)
throws IOException { throws IOException {
newSCPUploadClient().copy(localFile, remotePath); newSCPUploadClient().copy(localFile, remotePath);
} }

View File

@@ -16,7 +16,7 @@
package net.schmizz.sshj.xfer.scp; package net.schmizz.sshj.xfer.scp;
import net.schmizz.sshj.common.IOUtils; import net.schmizz.sshj.common.IOUtils;
import net.schmizz.sshj.xfer.LocalFile; import net.schmizz.sshj.xfer.LocalSourceFile;
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg; import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;
import java.io.IOException; import java.io.IOException;
@@ -34,7 +34,7 @@ public final class SCPUploadClient {
} }
/** Upload a local file from {@code localFile} to {@code targetPath} on the remote host. */ /** Upload a local file from {@code localFile} to {@code targetPath} on the remote host. */
public synchronized int copy(LocalFile sourceFile, String remotePath) public synchronized int copy(LocalSourceFile sourceFile, String remotePath)
throws IOException { throws IOException {
engine.cleanSlate(); engine.cleanSlate();
try { try {
@@ -45,48 +45,48 @@ public final class SCPUploadClient {
return engine.getExitStatus(); return engine.getExitStatus();
} }
private synchronized void startCopy(LocalFile sourceFile, String targetPath) private synchronized void startCopy(LocalSourceFile sourceFile, String targetPath)
throws IOException { throws IOException {
List<Arg> args = new LinkedList<Arg>(); List<Arg> args = new LinkedList<Arg>();
args.add(Arg.SINK); args.add(Arg.SINK);
args.add(Arg.RECURSIVE); args.add(Arg.RECURSIVE);
if (sourceFile.preservesTimes()) if (sourceFile.providesAtimeMtime())
args.add(Arg.PRESERVE_TIMES); args.add(Arg.PRESERVE_TIMES);
engine.execSCPWith(args, targetPath); engine.execSCPWith(args, targetPath);
engine.check("Start status OK"); engine.check("Start status OK");
process(sourceFile); process(sourceFile);
} }
private void process(LocalFile f) private void process(LocalSourceFile f)
throws IOException { throws IOException {
if (f.isDirectory()) { if (f.isDirectory()) {
engine.startedDir(f); engine.startedDir(f.getName());
sendDirectory(f); sendDirectory(f);
engine.finishedDir(); engine.finishedDir();
} else if (f.isFile()) { } else if (f.isFile()) {
engine.startedFile(f); engine.startedFile(f.getName(), f.getLength());
sendFile(f); sendFile(f);
engine.finishedFile(); engine.finishedFile();
} else } else
throw new IOException(f + " is not a regular file or directory"); throw new IOException(f + " is not a regular file or directory");
} }
private void sendDirectory(LocalFile f) private void sendDirectory(LocalSourceFile f)
throws IOException { throws IOException {
preserveTimeIfPossible(f); preserveTimeIfPossible(f);
engine.sendMessage("D0" + getPermString(f) + " 0 " + f.getName()); engine.sendMessage("D0" + getPermString(f) + " 0 " + f.getName());
for (LocalFile child : f.getChildren()) for (LocalSourceFile child : f.getChildren(null))
process(child); process(child);
engine.sendMessage("E"); engine.sendMessage("E");
} }
private void sendFile(LocalFile f) private void sendFile(LocalSourceFile f)
throws IOException { throws IOException {
preserveTimeIfPossible(f); preserveTimeIfPossible(f);
final InputStream src = f.getInputStream(); final InputStream src = f.getInputStream();
try { try {
engine.sendMessage("C0" + getPermString(f) + " " + f.length() + " " + f.getName()); engine.sendMessage("C0" + getPermString(f) + " " + f.getLength() + " " + f.getName());
engine.transferToRemote(f, src); engine.transferToRemote(src, f.getLength());
engine.signal("Transfer done"); engine.signal("Transfer done");
engine.check("Remote agrees transfer done"); engine.check("Remote agrees transfer done");
} finally { } finally {
@@ -94,13 +94,13 @@ public final class SCPUploadClient {
} }
} }
private void preserveTimeIfPossible(LocalFile f) private void preserveTimeIfPossible(LocalSourceFile f)
throws IOException { throws IOException {
if (f.preservesTimes()) if (f.providesAtimeMtime())
engine.sendMessage("T" + f.getLastModifiedTime() + " 0 " + f.getLastAccessTime() + " 0"); engine.sendMessage("T" + f.getLastModifiedTime() + " 0 " + f.getLastAccessTime() + " 0");
} }
private String getPermString(LocalFile f) private String getPermString(LocalSourceFile f)
throws IOException { throws IOException {
return Integer.toOctalString(f.getPermissions() & 07777); return Integer.toOctalString(f.getPermissions() & 07777);
} }