mirror of
https://github.com/hierynomus/sshj.git
synced 2025-12-08 08:10:55 +03:00
Carrying on with the file transfer interface refactoring
* Got rid of ModeGetter/ModeSetter, moved that to LocalFile * Instead of InMemoryFile now InMemorySourceFile (wraps istream) and InMemoryDestFile (wraps ostream) * Uploading with a LocalFile instance rather than String path
This commit is contained in:
@@ -16,6 +16,7 @@
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import net.schmizz.sshj.xfer.FilePermission;
|
||||
import net.schmizz.sshj.xfer.LocalFile;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
@@ -238,6 +239,16 @@ public class SFTPClient
|
||||
xfer.upload(source, dest);
|
||||
}
|
||||
|
||||
public void get(String source, LocalFile dest)
|
||||
throws IOException {
|
||||
xfer.download(source, dest);
|
||||
}
|
||||
|
||||
public void put(LocalFile source, String dest)
|
||||
throws IOException {
|
||||
xfer.upload(source, dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close()
|
||||
throws IOException {
|
||||
|
||||
@@ -15,22 +15,20 @@
|
||||
*/
|
||||
package net.schmizz.sshj.sftp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.EnumSet;
|
||||
|
||||
import net.schmizz.sshj.common.StreamCopier;
|
||||
import net.schmizz.sshj.sftp.Response.StatusCode;
|
||||
import net.schmizz.sshj.xfer.AbstractFileTransfer;
|
||||
import net.schmizz.sshj.xfer.FileSystemFile;
|
||||
import net.schmizz.sshj.xfer.FileTransfer;
|
||||
import net.schmizz.sshj.xfer.FileTransferUtil;
|
||||
import net.schmizz.sshj.xfer.LocalFile;
|
||||
import net.schmizz.sshj.xfer.LocalFileFilter;
|
||||
import net.schmizz.sshj.xfer.TransferListener;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.EnumSet;
|
||||
|
||||
public class SFTPFileTransfer
|
||||
extends AbstractFileTransfer
|
||||
implements FileTransfer {
|
||||
@@ -38,22 +36,8 @@ public class SFTPFileTransfer
|
||||
private final SFTPEngine engine;
|
||||
private final PathHelper pathHelper;
|
||||
|
||||
private volatile FileFilter uploadFilter = defaultLocalFilter;
|
||||
private volatile RemoteResourceFilter downloadFilter = defaultRemoteFilter;
|
||||
|
||||
private static final FileFilter defaultLocalFilter = new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File pathName) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
private static final RemoteResourceFilter defaultRemoteFilter = new RemoteResourceFilter() {
|
||||
@Override
|
||||
public boolean accept(RemoteResourceInfo resource) {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
private volatile LocalFileFilter uploadFilter;
|
||||
private volatile RemoteResourceFilter downloadFilter;
|
||||
|
||||
public SFTPFileTransfer(SFTPEngine engine) {
|
||||
this.engine = engine;
|
||||
@@ -65,30 +49,36 @@ public class SFTPFileTransfer
|
||||
throws IOException {
|
||||
new Uploader().upload(new FileSystemFile(source), dest);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(LocalFile localFile, String remotePath)
|
||||
throws IOException {
|
||||
new Uploader().upload(localFile, remotePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String source, String dest)
|
||||
throws IOException {
|
||||
final PathComponents pathComponents = pathHelper.getComponents(source);
|
||||
final FileAttributes attributes = engine.stat(source);
|
||||
new Downloader().download(new RemoteResourceInfo(pathComponents, attributes), new File(dest));
|
||||
download(source, new FileSystemFile(dest));
|
||||
}
|
||||
|
||||
public void setUploadFilter(FileFilter uploadFilter) {
|
||||
this.uploadFilter = (this.uploadFilter == null) ? defaultLocalFilter : uploadFilter;
|
||||
@Override
|
||||
public void upload(LocalFile localFile, String remotePath)
|
||||
throws IOException {
|
||||
new Uploader().upload(localFile, remotePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String source, LocalFile dest)
|
||||
throws IOException {
|
||||
final PathComponents pathComponents = pathHelper.getComponents(source);
|
||||
final FileAttributes attributes = engine.stat(source);
|
||||
new Downloader().download(new RemoteResourceInfo(pathComponents, attributes), dest);
|
||||
}
|
||||
|
||||
public void setUploadFilter(LocalFileFilter uploadFilter) {
|
||||
this.uploadFilter = uploadFilter;
|
||||
}
|
||||
|
||||
public void setDownloadFilter(RemoteResourceFilter downloadFilter) {
|
||||
this.downloadFilter = (this.downloadFilter == null) ? defaultRemoteFilter : downloadFilter;
|
||||
this.downloadFilter = downloadFilter;
|
||||
}
|
||||
|
||||
public FileFilter getUploadFilter() {
|
||||
public LocalFileFilter getUploadFilter() {
|
||||
return uploadFilter;
|
||||
}
|
||||
|
||||
@@ -100,9 +90,9 @@ public class SFTPFileTransfer
|
||||
|
||||
private final TransferListener listener = getTransferListener();
|
||||
|
||||
private void download(final RemoteResourceInfo remote, final File local)
|
||||
private void download(final RemoteResourceInfo remote, final LocalFile local)
|
||||
throws IOException {
|
||||
final File adjustedFile;
|
||||
final LocalFile adjustedFile;
|
||||
switch (remote.getAttributes().getType()) {
|
||||
case DIRECTORY:
|
||||
listener.startedDir(remote.getName());
|
||||
@@ -111,7 +101,7 @@ public class SFTPFileTransfer
|
||||
break;
|
||||
case UNKNOWN:
|
||||
log.warn("Server did not supply information about the type of file at `{}` " +
|
||||
"-- assuming it is a regular file!", remote.getPath());
|
||||
"-- assuming it is a regular file!", remote.getPath());
|
||||
case REGULAR:
|
||||
listener.startedFile(remote.getName(), remote.getAttributes().getSize());
|
||||
adjustedFile = downloadFile(remote, local);
|
||||
@@ -124,30 +114,30 @@ public class SFTPFileTransfer
|
||||
|
||||
}
|
||||
|
||||
private File downloadDir(final RemoteResourceInfo remote, final File local)
|
||||
private LocalFile downloadDir(final RemoteResourceInfo remote, final LocalFile local)
|
||||
throws IOException {
|
||||
final File adjusted = FileTransferUtil.getTargetDirectory(local, remote.getName());
|
||||
final LocalFile adjusted = local.getTargetDirectory(remote.getName());
|
||||
final RemoteDirectory rd = engine.openDir(remote.getPath());
|
||||
try {
|
||||
for (RemoteResourceInfo rri : rd.scan(getDownloadFilter()))
|
||||
download(rri, new File(adjusted.getPath(), rri.getName()));
|
||||
download(rri, adjusted.getChild(rri.getName()));
|
||||
} finally {
|
||||
rd.close();
|
||||
}
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
private File downloadFile(final RemoteResourceInfo remote, final File local)
|
||||
private LocalFile downloadFile(final RemoteResourceInfo remote, final LocalFile local)
|
||||
throws IOException {
|
||||
final File adjusted = FileTransferUtil.getTargetFile(local, remote.getName());
|
||||
final LocalFile adjusted = local.getTargetFile(remote.getName());
|
||||
final RemoteFile rf = engine.open(remote.getPath());
|
||||
try {
|
||||
final FileOutputStream fos = new FileOutputStream(adjusted);
|
||||
final OutputStream os = adjusted.getOutputStream();
|
||||
try {
|
||||
StreamCopier.copy(rf.getInputStream(), fos, engine.getSubsystem()
|
||||
.getLocalMaxPacketSize(), false, listener);
|
||||
StreamCopier.copy(rf.getInputStream(), os,
|
||||
engine.getSubsystem().getLocalMaxPacketSize(), false, listener);
|
||||
} finally {
|
||||
fos.close();
|
||||
os.close();
|
||||
}
|
||||
} finally {
|
||||
rf.close();
|
||||
@@ -155,13 +145,13 @@ public class SFTPFileTransfer
|
||||
return adjusted;
|
||||
}
|
||||
|
||||
private void copyAttributes(final RemoteResourceInfo remote, final File local)
|
||||
private void copyAttributes(final RemoteResourceInfo remote, final LocalFile local)
|
||||
throws IOException {
|
||||
final FileAttributes attrs = remote.getAttributes();
|
||||
getModeSetter().setPermissions(local, attrs.getMode().getPermissionsMask());
|
||||
if (getModeSetter().preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) {
|
||||
getModeSetter().setLastAccessedTime(local, attrs.getAtime());
|
||||
getModeSetter().setLastModifiedTime(local, attrs.getMtime());
|
||||
local.setPermissions(attrs.getMode().getPermissionsMask());
|
||||
if (local.preservesTimes() && attrs.has(FileAttributes.Flag.ACMODTIME)) {
|
||||
local.setLastAccessedTime(attrs.getAtime());
|
||||
local.setLastModifiedTime(attrs.getMtime());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -202,7 +192,7 @@ public class SFTPFileTransfer
|
||||
OpenMode.CREAT,
|
||||
OpenMode.TRUNC));
|
||||
try {
|
||||
final InputStream fis = local.stream();
|
||||
final InputStream fis = local.getInputStream();
|
||||
try {
|
||||
final int bufSize = engine.getSubsystem().getRemoteMaxPacketSize() - rf.getOutgoingPacketOverhead();
|
||||
StreamCopier.copy(fis, rf.getOutputStream(), bufSize, false, listener);
|
||||
@@ -265,10 +255,9 @@ public class SFTPFileTransfer
|
||||
|
||||
private FileAttributes getAttributes(LocalFile local)
|
||||
throws IOException {
|
||||
final FileAttributes.Builder builder = new FileAttributes.Builder()
|
||||
.withPermissions(getModeGetter().getPermissions(local));
|
||||
if (getModeGetter().preservesTimes())
|
||||
builder.withAtimeMtime(getModeGetter().getLastAccessTime(local), getModeGetter().getLastModifiedTime(local));
|
||||
final FileAttributes.Builder builder = new FileAttributes.Builder().withPermissions(local.getPermissions());
|
||||
if (local.preservesTimes())
|
||||
builder.withAtimeMtime(local.getLastAccessTime(), local.getLastModifiedTime());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,30 +22,10 @@ public abstract class AbstractFileTransfer {
|
||||
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
public static final ModeGetter DEFAULT_MODE_SETTER = new DefaultModeGetter();
|
||||
public static final ModeSetter DEFAULT_MODE_GETTER = new DefaultModeSetter();
|
||||
public static final LoggingTransferListener LOGGING_TRANSFER_LISTENER = new LoggingTransferListener();
|
||||
|
||||
private volatile ModeGetter modeGetter = DEFAULT_MODE_SETTER;
|
||||
private volatile ModeSetter modeSetter = DEFAULT_MODE_GETTER;
|
||||
private volatile TransferListener transferListener = LOGGING_TRANSFER_LISTENER;
|
||||
|
||||
public void setModeGetter(ModeGetter modeGetter) {
|
||||
this.modeGetter = (modeGetter == null) ? DEFAULT_MODE_SETTER : modeGetter;
|
||||
}
|
||||
|
||||
public ModeGetter getModeGetter() {
|
||||
return this.modeGetter;
|
||||
}
|
||||
|
||||
public void setModeSetter(ModeSetter modeSetter) {
|
||||
this.modeSetter = (modeSetter == null) ? DEFAULT_MODE_GETTER : modeSetter;
|
||||
}
|
||||
|
||||
public ModeSetter getModeSetter() {
|
||||
return this.modeSetter;
|
||||
}
|
||||
|
||||
public TransferListener getTransferListener() {
|
||||
return transferListener;
|
||||
}
|
||||
@@ -54,4 +34,4 @@ public abstract class AbstractFileTransfer {
|
||||
this.transferListener = (transferListener == null) ? LOGGING_TRANSFER_LISTENER : transferListener;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,76 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 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.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ModeGetter} that supplies file permissions as {@code "0644"}, directory permissions
|
||||
* as {@code "0755"}, and preserves timestamps. Note that there is no way of getting the last access time with Java file
|
||||
* API's so it is returned as the current system time.
|
||||
*/
|
||||
public class DefaultModeGetter
|
||||
implements ModeGetter {
|
||||
|
||||
@Override
|
||||
public long getLastAccessTime(File f) {
|
||||
return System.currentTimeMillis() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModifiedTime(File f) {
|
||||
return f.lastModified() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPermissions(File f)
|
||||
throws IOException {
|
||||
if (f.isDirectory())
|
||||
return 0755;
|
||||
else if (f.isFile())
|
||||
return 0644;
|
||||
else
|
||||
throw new IOException("Unsupported file type: " + f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAccessTime(LocalFile f) {
|
||||
return System.currentTimeMillis() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModifiedTime(LocalFile f) {
|
||||
return f.lastModified() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPermissions(LocalFile f)
|
||||
throws IOException {
|
||||
if (f.isDirectory())
|
||||
return 0755;
|
||||
else if (f.isFile())
|
||||
return 0644;
|
||||
else
|
||||
throw new IOException("Unsupported file type: " + f);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preservesTimes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,65 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Default implementation of {@link ModeSetter} attempts to preserve timestamps and permissions to the extent allowed by
|
||||
* Java File API.
|
||||
*/
|
||||
public class DefaultModeSetter
|
||||
implements ModeSetter {
|
||||
|
||||
private final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
@Override
|
||||
public void setLastAccessedTime(File f, long t)
|
||||
throws IOException {
|
||||
// Can't do anything
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModifiedTime(File f, long t)
|
||||
throws IOException {
|
||||
if (!f.setLastModified(t * 1000))
|
||||
log.warn("Could not set last modified time for {} to {}", f, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissions(File f, int perms)
|
||||
throws IOException {
|
||||
final boolean r = f.setReadable(FilePermission.USR_R.isIn(perms),
|
||||
!(FilePermission.OTH_R.isIn(perms) || FilePermission.GRP_R.isIn(perms)));
|
||||
final boolean w = f.setWritable(FilePermission.USR_W.isIn(perms),
|
||||
!(FilePermission.OTH_W.isIn(perms) || FilePermission.GRP_W.isIn(perms)));
|
||||
final boolean x = f.setExecutable(FilePermission.USR_X.isIn(perms),
|
||||
!(FilePermission.OTH_X.isIn(perms) || FilePermission.GRP_X.isIn(perms)));
|
||||
if (!(r && w && x))
|
||||
log.warn("Could not set permissions for {} to {}", f, Integer.toString(perms, 16));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preservesTimes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,80 +15,210 @@
|
||||
*/
|
||||
package net.schmizz.sshj.xfer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileFilter;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class FileSystemFile
|
||||
implements LocalFile {
|
||||
|
||||
public class FileSystemFile implements LocalFile {
|
||||
protected final Logger log = LoggerFactory.getLogger(getClass());
|
||||
|
||||
private File file;
|
||||
private FileFilter fileFilter;
|
||||
private final File file;
|
||||
|
||||
public FileSystemFile(String path) {
|
||||
this.file = new File(path);
|
||||
}
|
||||
|
||||
public void setFileFilter(FileFilter fileFilter) {
|
||||
this.fileFilter = fileFilter;
|
||||
}
|
||||
public FileSystemFile(String path) {
|
||||
this(new File(path));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return file.getName();
|
||||
}
|
||||
public FileSystemFile(File file) {
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return file.isDirectory();
|
||||
}
|
||||
public File getFile() {
|
||||
return file;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return file.isFile();
|
||||
}
|
||||
@Override
|
||||
public String getName() {
|
||||
return file.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() {
|
||||
return file.length();
|
||||
}
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return file.isFile();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long lastModified() {
|
||||
return file.lastModified();
|
||||
}
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return file.isDirectory();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream stream() throws IOException {
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
@Override
|
||||
public long length() {
|
||||
return file.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<LocalFile> getChildren() throws IOException {
|
||||
return getChildren(file);
|
||||
}
|
||||
@Override
|
||||
public InputStream getInputStream()
|
||||
throws IOException {
|
||||
return new FileInputStream(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream()
|
||||
throws IOException {
|
||||
return new FileOutputStream(file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FileSystemFile> getChildren()
|
||||
throws IOException {
|
||||
return getChildren(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<FileSystemFile> getChildren(final LocalFileFilter filter)
|
||||
throws IOException {
|
||||
final Map<File, FileSystemFile> cache = new HashMap<File, FileSystemFile>();
|
||||
|
||||
File[] childFiles = filter == null ? file.listFiles() : file.listFiles(new FileFilter() {
|
||||
@Override
|
||||
public boolean accept(File file) {
|
||||
final FileSystemFile fsf = new FileSystemFile(file);
|
||||
cache.put(file, fsf);
|
||||
return filter.accept(fsf);
|
||||
}
|
||||
});
|
||||
|
||||
if (childFiles == null)
|
||||
throw new IOException("Error listing files in directory: " + this);
|
||||
|
||||
final List<FileSystemFile> children = new ArrayList<FileSystemFile>();
|
||||
for (File f : childFiles) {
|
||||
children.add(cache.get(f));
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastAccessTime()
|
||||
throws IOException {
|
||||
return System.currentTimeMillis() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLastModifiedTime()
|
||||
throws IOException {
|
||||
return file.lastModified() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPermissions()
|
||||
throws IOException {
|
||||
if (isDirectory())
|
||||
return 0755;
|
||||
else if (isFile())
|
||||
return 0644;
|
||||
else
|
||||
throw new IOException("Unsupported file type");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastAccessedTime(long t)
|
||||
throws IOException {
|
||||
// ...
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLastModifiedTime(long t)
|
||||
throws IOException {
|
||||
if (!file.setLastModified(t * 1000))
|
||||
log.warn("Could not set last modified time for {} to {}", file, t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPermissions(int perms)
|
||||
throws IOException {
|
||||
final boolean r = file.setReadable(FilePermission.USR_R.isIn(perms),
|
||||
!(FilePermission.OTH_R.isIn(perms) || FilePermission.GRP_R.isIn(perms)));
|
||||
final boolean w = file.setWritable(FilePermission.USR_W.isIn(perms),
|
||||
!(FilePermission.OTH_W.isIn(perms) || FilePermission.GRP_W.isIn(perms)));
|
||||
final boolean x = file.setExecutable(FilePermission.USR_X.isIn(perms),
|
||||
!(FilePermission.OTH_X.isIn(perms) || FilePermission.GRP_X.isIn(perms)));
|
||||
if (!(r && w && x))
|
||||
log.warn("Could not set permissions for {} to {}", file, Integer.toString(perms, 16));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean preservesTimes() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemFile getChild(String name) {
|
||||
return new FileSystemFile(new File(file, name));
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemFile getTargetFile(String filename)
|
||||
throws IOException {
|
||||
FileSystemFile f = this;
|
||||
|
||||
if (f.isDirectory())
|
||||
f = f.getChild(filename);
|
||||
|
||||
if (!f.getFile().exists()) {
|
||||
if (!f.getFile().createNewFile())
|
||||
throw new IOException("Could not create: " + file);
|
||||
} else if (f.isDirectory())
|
||||
throw new IOException("A directory by the same name already exists: " + f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileSystemFile getTargetDirectory(String dirname)
|
||||
throws IOException {
|
||||
FileSystemFile f = this;
|
||||
|
||||
if (f.getFile().exists())
|
||||
if (f.isDirectory()) {
|
||||
if (!f.getName().equals(dirname))
|
||||
f = f.getChild(dirname);
|
||||
} else
|
||||
throw new IOException(f + " - already exists as a file; directory required");
|
||||
|
||||
if (!f.getFile().exists() && !f.getFile().mkdir())
|
||||
throw new IOException("Failed to create directory: " + f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object other) {
|
||||
return (other instanceof FileSystemFile)
|
||||
&& file.equals(((FileSystemFile) other).file);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return file != null ? file.hashCode() : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return file.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<LocalFile> getChildren(FileFilter filter) throws IOException {
|
||||
setFileFilter(filter);
|
||||
return getChildren(file);
|
||||
}
|
||||
|
||||
private Iterable<LocalFile> getChildren(File f) throws IOException {
|
||||
Collection<LocalFile> files = new ArrayList<LocalFile>();
|
||||
File[] childFiles = fileFilter == null ? f.listFiles() : f.listFiles(fileFilter);
|
||||
if (childFiles == null)
|
||||
throw new IOException("Error listing files in directory: " + f);
|
||||
|
||||
for (File childFile : childFiles) {
|
||||
FileSystemFile localChild = new FileSystemFile(childFile.getName());
|
||||
localChild.setFileFilter(fileFilter);
|
||||
files.add(localChild);
|
||||
}
|
||||
return files;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,19 +22,14 @@ public interface FileTransfer {
|
||||
void upload(String localPath, String remotePath)
|
||||
throws IOException;
|
||||
|
||||
void upload(LocalFile localFile, String remotePath)
|
||||
throws IOException;
|
||||
|
||||
void download(String remotePath, String localPath)
|
||||
throws IOException;
|
||||
|
||||
ModeGetter getModeGetter();
|
||||
void upload(LocalFile localFile, String remotePath)
|
||||
throws IOException;
|
||||
|
||||
void setModeGetter(ModeGetter modeGetter);
|
||||
|
||||
ModeSetter getModeSetter();
|
||||
|
||||
void setModeSetter(ModeSetter modeSetter);
|
||||
void download(String remotePath, LocalFile localFile)
|
||||
throws IOException;
|
||||
|
||||
TransferListener getTransferListener();
|
||||
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 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.File;
|
||||
import java.io.IOException;
|
||||
|
||||
public class FileTransferUtil {
|
||||
|
||||
public static File getTargetDirectory(File f, String dirname)
|
||||
throws IOException {
|
||||
if (f.exists())
|
||||
if (f.isDirectory()) {
|
||||
if (!f.getName().equals(dirname))
|
||||
f = new File(f, dirname);
|
||||
} else
|
||||
throw new IOException(f + " - already exists as a file; directory required");
|
||||
|
||||
if (!f.exists() && !f.mkdir())
|
||||
throw new IOException("Failed to create directory: " + f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
public static File getTargetFile(File f, String filename)
|
||||
throws IOException {
|
||||
if (f.isDirectory())
|
||||
f = new File(f, filename);
|
||||
|
||||
if (!f.exists()) {
|
||||
if (!f.createNewFile())
|
||||
throw new IOException("Could not create: " + f);
|
||||
} else if (f.isDirectory())
|
||||
throw new IOException("A directory by the same name already exists: " + f);
|
||||
|
||||
return f;
|
||||
}
|
||||
|
||||
}
|
||||
141
src/main/java/net/schmizz/sshj/xfer/InMemoryDestFile.java
Normal file
141
src/main/java/net/schmizz/sshj/xfer/InMemoryDestFile.java
Normal file
@@ -0,0 +1,141 @@
|
||||
/*
|
||||
* Copyright 2010, 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class InMemoryDestFile
|
||||
implements LocalFile {
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
public void setLastAccessedTime(long t)
|
||||
throws IOException {
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,97 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 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.ByteArrayInputStream;
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.Collections;
|
||||
|
||||
public class InMemoryFile implements LocalFile {
|
||||
|
||||
private static final int EOF = -1;
|
||||
private static final int DEFAULT_BUFFER_SIZE = 4096;
|
||||
|
||||
private String name;
|
||||
private Long cachedLength;
|
||||
private InputStream stream;
|
||||
|
||||
public InMemoryFile(String filename, ByteArrayInputStream stream) {
|
||||
this.name = filename;
|
||||
this.stream = stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() {
|
||||
if (cachedLength == null) {
|
||||
cachedLength = computeLength();
|
||||
}
|
||||
return cachedLength;
|
||||
}
|
||||
|
||||
private long computeLength() {
|
||||
try {
|
||||
byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];
|
||||
long length = 0;
|
||||
int readBytes = 0;
|
||||
while (EOF != (readBytes = stream.read(buffer))) {
|
||||
length += readBytes;
|
||||
}
|
||||
stream.reset();
|
||||
return length;
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException("Impossible to read in memory file", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public long lastModified() {
|
||||
return System.currentTimeMillis() / 1000;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream stream() {
|
||||
return stream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<LocalFile> getChildren() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Iterable<LocalFile> getChildren(FileFilter filter)
|
||||
throws IOException {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
}
|
||||
143
src/main/java/net/schmizz/sshj/xfer/InMemorySourceFile.java
Normal file
143
src/main/java/net/schmizz/sshj/xfer/InMemorySourceFile.java
Normal file
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright 2010, 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 org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class InMemorySourceFile
|
||||
implements LocalFile {
|
||||
|
||||
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
|
||||
public boolean isFile() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDirectory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long length() {
|
||||
return length;
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getInputStream()
|
||||
throws IOException {
|
||||
return inStream;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPermissions()
|
||||
throws IOException {
|
||||
return 0644;
|
||||
}
|
||||
|
||||
// Everything else is unimplemented
|
||||
|
||||
@Override
|
||||
public OutputStream getOutputStream()
|
||||
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 void setLastAccessedTime(long t)
|
||||
throws IOException {
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,24 +15,100 @@
|
||||
*/
|
||||
package net.schmizz.sshj.xfer;
|
||||
|
||||
import java.io.FileFilter;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
|
||||
// TODO Document all methods properly
|
||||
|
||||
public interface LocalFile {
|
||||
|
||||
String getName();
|
||||
String getName();
|
||||
|
||||
boolean isDirectory();
|
||||
boolean isFile();
|
||||
|
||||
boolean isDirectory();
|
||||
|
||||
long length();
|
||||
|
||||
long lastModified();
|
||||
|
||||
InputStream stream() throws IOException;
|
||||
InputStream getInputStream() throws IOException;
|
||||
|
||||
Iterable<LocalFile> getChildren() throws IOException;
|
||||
Iterable<LocalFile> getChildren(FileFilter filter) 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.
|
||||
*
|
||||
* @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;
|
||||
|
||||
/**
|
||||
* Returns the permissions for the underlying file
|
||||
*
|
||||
* @return permissions in octal format, e.g. 0644
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
int getPermissions()
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Set the last access time for the underlying file.
|
||||
*
|
||||
* @param t time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void setLastAccessedTime(long t)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Set the last modified time for the underlying file.
|
||||
*
|
||||
* @param f the file
|
||||
* @param t time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void setLastModifiedTime(long t)
|
||||
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;
|
||||
|
||||
}
|
||||
22
src/main/java/net/schmizz/sshj/xfer/LocalFileFilter.java
Normal file
22
src/main/java/net/schmizz/sshj/xfer/LocalFileFilter.java
Normal file
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* Copyright 2010, 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;
|
||||
|
||||
public interface LocalFileFilter {
|
||||
|
||||
boolean accept(LocalFile file);
|
||||
|
||||
}
|
||||
@@ -1,101 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 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.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/** An interface for retrieving information about file permissions and times. */
|
||||
public interface ModeGetter {
|
||||
|
||||
/**
|
||||
* Returns last access time for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
*
|
||||
* @return time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
long getLastAccessTime(File f)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns last modified time for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
*
|
||||
* @return time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
long getLastModifiedTime(File f)
|
||||
throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the permissions for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
*
|
||||
* @return permissions in octal format, e.g. 0644
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
int getPermissions(File f)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns last access time for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
*
|
||||
* @return time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
long getLastAccessTime(LocalFile f)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Returns last modified time for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
*
|
||||
* @return time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
long getLastModifiedTime(LocalFile f)
|
||||
throws IOException;
|
||||
|
||||
|
||||
/**
|
||||
* Returns the permissions for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
*
|
||||
* @return permissions in octal format, e.g. 0644
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
int getPermissions(LocalFile f)
|
||||
throws IOException;
|
||||
|
||||
/** @return whether this implementation can provide mtime and atime information. */
|
||||
boolean preservesTimes();
|
||||
|
||||
}
|
||||
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010, 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.File;
|
||||
import java.io.IOException;
|
||||
|
||||
/** An interface for setting file permissions and times. */
|
||||
public interface ModeSetter {
|
||||
|
||||
/**
|
||||
* Set the last access time for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
* @param t time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void setLastAccessedTime(File f, long t)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Set the last modified time for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
* @param t time in seconds since Unix epoch
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void setLastModifiedTime(File f, long t)
|
||||
throws IOException;
|
||||
|
||||
/**
|
||||
* Set the permissions for {@code f}.
|
||||
*
|
||||
* @param f the file
|
||||
* @param perms permissions in octal format, e.g. "644"
|
||||
*
|
||||
* @throws IOException
|
||||
*/
|
||||
void setPermissions(File f, int perms)
|
||||
throws IOException;
|
||||
|
||||
/** @return whether this implementation is interested in preserving mtime and atime. */
|
||||
boolean preservesTimes();
|
||||
|
||||
}
|
||||
@@ -15,38 +15,32 @@
|
||||
*/
|
||||
package net.schmizz.sshj.xfer.scp;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
import net.schmizz.sshj.xfer.FileTransferUtil;
|
||||
import net.schmizz.sshj.xfer.ModeSetter;
|
||||
import net.schmizz.sshj.xfer.LocalFile;
|
||||
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;
|
||||
|
||||
/** Support for uploading files over a connected link using SCP. */
|
||||
public final class SCPDownloadClient {
|
||||
|
||||
private final ModeSetter modeSetter;
|
||||
|
||||
private boolean recursive = true;
|
||||
|
||||
private SCPEngine engine;
|
||||
|
||||
SCPDownloadClient(SCPEngine engine, ModeSetter modeSetter) {
|
||||
SCPDownloadClient(SCPEngine engine) {
|
||||
this.engine = engine;
|
||||
this.modeSetter = modeSetter;
|
||||
}
|
||||
|
||||
/** Download a file from {@code sourcePath} on the connected host to {@code targetPath} locally. */
|
||||
public synchronized int copy(String sourcePath, String targetPath)
|
||||
public synchronized int copy(String sourcePath, LocalFile targetFile)
|
||||
throws IOException {
|
||||
engine.cleanSlate();
|
||||
try {
|
||||
startCopy(sourcePath, targetPath);
|
||||
startCopy(sourcePath, targetFile);
|
||||
} finally {
|
||||
engine.exit();
|
||||
}
|
||||
@@ -61,28 +55,23 @@ public final class SCPDownloadClient {
|
||||
this.recursive = recursive;
|
||||
}
|
||||
|
||||
void startCopy(String sourcePath, String targetPath)
|
||||
void startCopy(String sourcePath, LocalFile targetFile)
|
||||
throws IOException {
|
||||
init(sourcePath);
|
||||
|
||||
engine.signal("Start status OK");
|
||||
|
||||
String msg = engine.readMessage(true);
|
||||
do
|
||||
process(null, msg, new File(targetPath));
|
||||
while ((msg = engine.readMessage(false)) != null);
|
||||
}
|
||||
|
||||
private void init(String source)
|
||||
throws SSHException {
|
||||
List<Arg> args = new LinkedList<Arg>();
|
||||
args.add(Arg.SOURCE);
|
||||
args.add(Arg.QUIET);
|
||||
if (recursive)
|
||||
args.add(Arg.RECURSIVE);
|
||||
if (modeSetter.preservesTimes())
|
||||
if (targetFile.preservesTimes())
|
||||
args.add(Arg.PRESERVE_TIMES);
|
||||
engine.execSCPWith(args, source);
|
||||
engine.execSCPWith(args, sourcePath);
|
||||
|
||||
engine.signal("Start status OK");
|
||||
|
||||
String msg = engine.readMessage(true);
|
||||
do
|
||||
process(null, msg, targetFile);
|
||||
while ((msg = engine.readMessage(false)) != null);
|
||||
}
|
||||
|
||||
private long parseLong(String longString, String valType)
|
||||
@@ -103,7 +92,7 @@ public final class SCPDownloadClient {
|
||||
return Integer.parseInt(cmd.substring(1), 8);
|
||||
}
|
||||
|
||||
private boolean process(String bufferedTMsg, String msg, File f)
|
||||
private boolean process(String bufferedTMsg, String msg, LocalFile f)
|
||||
throws IOException {
|
||||
if (msg.length() < 1)
|
||||
throw new SCPException("Could not parse message `" + msg + "`");
|
||||
@@ -139,7 +128,7 @@ public final class SCPDownloadClient {
|
||||
return false;
|
||||
}
|
||||
|
||||
private void processDirectory(String dMsg, String tMsg, File f)
|
||||
private void processDirectory(String dMsg, String tMsg, LocalFile f)
|
||||
throws IOException {
|
||||
final String[] dMsgParts = tokenize(dMsg, 3); // D<perms> 0 <dirname>
|
||||
final long length = parseLong(dMsgParts[1], "dir length");
|
||||
@@ -148,7 +137,7 @@ public final class SCPDownloadClient {
|
||||
throw new IOException("Remote SCP command sent strange directory length: " + length);
|
||||
engine.startedDir(dirname);
|
||||
{
|
||||
f = FileTransferUtil.getTargetDirectory(f, dirname);
|
||||
f = f.getTargetDirectory(dirname);
|
||||
engine.signal("ACK: D");
|
||||
do {
|
||||
} while (!process(null, engine.readMessage(), f));
|
||||
@@ -158,20 +147,20 @@ public final class SCPDownloadClient {
|
||||
engine.finishedDir();
|
||||
}
|
||||
|
||||
private void processFile(String cMsg, String tMsg, File f)
|
||||
private void processFile(String cMsg, String tMsg, LocalFile f)
|
||||
throws IOException {
|
||||
final String[] cMsgParts = tokenize(cMsg, 3); // C<perms> <size> <filename>
|
||||
final long length = parseLong(cMsgParts[1], "length");
|
||||
final String filename = cMsgParts[2];
|
||||
engine.startedFile(length, filename);
|
||||
{
|
||||
f = FileTransferUtil.getTargetFile(f, filename);
|
||||
f = f.getTargetFile(filename);
|
||||
engine.signal("Remote can start transfer");
|
||||
final FileOutputStream fos = new FileOutputStream(f);
|
||||
final OutputStream os = f.getOutputStream();
|
||||
try {
|
||||
engine.transfertFromRemote(length, fos);
|
||||
engine.transferFromRemote(length, os);
|
||||
} finally {
|
||||
IOUtils.closeQuietly(fos);
|
||||
IOUtils.closeQuietly(os);
|
||||
}
|
||||
engine.check("Remote agrees transfer done");
|
||||
setAttributes(f, parsePermissions(cMsgParts[0]), tMsg);
|
||||
@@ -180,13 +169,13 @@ public final class SCPDownloadClient {
|
||||
engine.finishedFile();
|
||||
}
|
||||
|
||||
private void setAttributes(File f, int perms, String tMsg)
|
||||
private void setAttributes(LocalFile f, int perms, String tMsg)
|
||||
throws IOException {
|
||||
modeSetter.setPermissions(f, perms);
|
||||
if (tMsg != null && modeSetter.preservesTimes()) {
|
||||
f.setPermissions(perms);
|
||||
if (tMsg != null && f.preservesTimes()) {
|
||||
String[] tMsgParts = tokenize(tMsg, 4); // e.g. T<mtime> 0 <atime> 0
|
||||
modeSetter.setLastModifiedTime(f, parseLong(tMsgParts[0].substring(1), "last modified time"));
|
||||
modeSetter.setLastAccessedTime(f, parseLong(tMsgParts[2], "last access time"));
|
||||
f.setLastModifiedTime(parseLong(tMsgParts[0].substring(1), "last modified time"));
|
||||
f.setLastAccessedTime(parseLong(tMsgParts[2], "last access time"));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,6 @@
|
||||
*/
|
||||
package net.schmizz.sshj.xfer.scp;
|
||||
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
@@ -162,14 +161,14 @@ class SCPEngine {
|
||||
scp.getOutputStream().flush();
|
||||
}
|
||||
|
||||
void transfertToRemote(LocalFile f, final InputStream src)
|
||||
void transferToRemote(LocalFile f, final InputStream src)
|
||||
throws IOException {
|
||||
transfer(src, scp.getOutputStream(), scp.getRemoteMaxPacketSize(), f.length());
|
||||
}
|
||||
|
||||
void transfertFromRemote(final long length, final FileOutputStream fos)
|
||||
void transferFromRemote(final long length, final OutputStream os)
|
||||
throws IOException {
|
||||
transfer(scp.getInputStream(), fos, scp.getLocalMaxPacketSize(), length);
|
||||
transfer(scp.getInputStream(), os, scp.getLocalMaxPacketSize(), length);
|
||||
}
|
||||
|
||||
private void transfer(InputStream in, OutputStream out, int bufSize, long len)
|
||||
@@ -218,4 +217,5 @@ class SCPEngine {
|
||||
void finishedFile() {
|
||||
listener.finishedFile();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -34,32 +34,39 @@ public class SCPFileTransfer
|
||||
}
|
||||
|
||||
public SCPDownloadClient newSCPDownloadClient() {
|
||||
return new SCPDownloadClient(getSCPEngine(), getModeSetter());
|
||||
return new SCPDownloadClient(newSCPEngine());
|
||||
}
|
||||
|
||||
public SCPUploadClient newSCPUploadClient() {
|
||||
return new SCPUploadClient(getSCPEngine(), getModeGetter());
|
||||
return new SCPUploadClient(newSCPEngine());
|
||||
}
|
||||
|
||||
private SCPEngine getSCPEngine() {
|
||||
private SCPEngine newSCPEngine() {
|
||||
return new SCPEngine(sessionFactory, getTransferListener());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String remotePath, String localPath)
|
||||
throws IOException {
|
||||
newSCPDownloadClient().copy(remotePath, localPath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(String localPath, String remotePath)
|
||||
throws IOException {
|
||||
newSCPUploadClient().copy(new FileSystemFile(localPath), remotePath);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String remotePath, String localPath)
|
||||
throws IOException {
|
||||
download(remotePath, new FileSystemFile(localPath));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void download(String remotePath, LocalFile localFile)
|
||||
throws IOException {
|
||||
newSCPDownloadClient().copy(remotePath, localFile);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void upload(LocalFile localFile, String remotePath)
|
||||
throws IOException {
|
||||
newSCPUploadClient().copy(localFile, remotePath);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -15,103 +15,94 @@
|
||||
*/
|
||||
package net.schmizz.sshj.xfer.scp;
|
||||
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.xfer.LocalFile;
|
||||
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import net.schmizz.sshj.common.IOUtils;
|
||||
import net.schmizz.sshj.common.SSHException;
|
||||
import net.schmizz.sshj.xfer.LocalFile;
|
||||
import net.schmizz.sshj.xfer.ModeGetter;
|
||||
import net.schmizz.sshj.xfer.scp.SCPEngine.Arg;
|
||||
|
||||
/** Support for uploading files over a connected link using SCP. */
|
||||
public final class SCPUploadClient {
|
||||
|
||||
private final ModeGetter modeGetter;
|
||||
|
||||
private SCPEngine engine;
|
||||
|
||||
SCPUploadClient(SCPEngine engine, ModeGetter modeGetter) {
|
||||
SCPUploadClient(SCPEngine engine) {
|
||||
this.engine = engine;
|
||||
this.modeGetter = modeGetter;
|
||||
}
|
||||
|
||||
/** Upload a local file from {@code localFile} to {@code targetPath} on the remote host. */
|
||||
public synchronized int copy(LocalFile sourceFile, String remotePath)
|
||||
throws IOException {
|
||||
engine.cleanSlate();
|
||||
try {
|
||||
startCopy(sourceFile, remotePath);
|
||||
} finally {
|
||||
engine.exit();
|
||||
}
|
||||
return engine.getExitStatus();
|
||||
public synchronized int copy(LocalFile sourceFile, String remotePath)
|
||||
throws IOException {
|
||||
engine.cleanSlate();
|
||||
try {
|
||||
startCopy(sourceFile, remotePath);
|
||||
} finally {
|
||||
engine.exit();
|
||||
}
|
||||
return engine.getExitStatus();
|
||||
}
|
||||
|
||||
private synchronized void startCopy(LocalFile sourceFile, String targetPath)
|
||||
throws IOException {
|
||||
init(targetPath);
|
||||
engine.check("Start status OK");
|
||||
process(sourceFile);
|
||||
}
|
||||
|
||||
private void init(String target)
|
||||
throws SSHException {
|
||||
throws IOException {
|
||||
List<Arg> args = new LinkedList<Arg>();
|
||||
args.add(Arg.SINK);
|
||||
args.add(Arg.RECURSIVE);
|
||||
if (modeGetter.preservesTimes())
|
||||
if (sourceFile.preservesTimes())
|
||||
args.add(Arg.PRESERVE_TIMES);
|
||||
engine.execSCPWith(args, target);
|
||||
engine.execSCPWith(args, targetPath);
|
||||
engine.check("Start status OK");
|
||||
process(sourceFile);
|
||||
}
|
||||
|
||||
private void process(LocalFile f)
|
||||
throws IOException {
|
||||
if (f.isDirectory()) {
|
||||
engine.startedDir(f);
|
||||
sendDirectory(f);
|
||||
engine.finishedDir();
|
||||
} else if (f.isFile()) {
|
||||
engine.startedFile(f);
|
||||
sendFile(f);
|
||||
engine.finishedFile();
|
||||
} else
|
||||
throw new IOException(f + " is not a regular file or directory");
|
||||
}
|
||||
throws IOException {
|
||||
if (f.isDirectory()) {
|
||||
engine.startedDir(f);
|
||||
sendDirectory(f);
|
||||
engine.finishedDir();
|
||||
} else if (f.isFile()) {
|
||||
engine.startedFile(f);
|
||||
sendFile(f);
|
||||
engine.finishedFile();
|
||||
} else
|
||||
throw new IOException(f + " is not a regular file or directory");
|
||||
}
|
||||
|
||||
private void sendDirectory(LocalFile f)
|
||||
throws IOException {
|
||||
preserveTimeIfPossible(f);
|
||||
engine.sendMessage("D0" + getPermString(f) + " 0 " + f.getName());
|
||||
for (LocalFile child : f.getChildren())
|
||||
process(child);
|
||||
engine.sendMessage("E");
|
||||
}
|
||||
|
||||
private void sendDirectory(LocalFile f)
|
||||
throws IOException {
|
||||
preserveTimeIfPossible(f);
|
||||
engine.sendMessage("D0" + getPermString(f) + " 0 " + f.getName());
|
||||
for (LocalFile child : f.getChildren())
|
||||
process(child);
|
||||
engine.sendMessage("E");
|
||||
}
|
||||
|
||||
private void sendFile(LocalFile f)
|
||||
throws IOException {
|
||||
preserveTimeIfPossible(f);
|
||||
final InputStream src = f.stream();
|
||||
try {
|
||||
engine.sendMessage("C0" + getPermString(f) + " " + f.length() + " " + f.getName());
|
||||
engine.transfertToRemote(f, src);
|
||||
engine.signal("Transfer done");
|
||||
engine.check("Remote agrees transfer done");
|
||||
} finally {
|
||||
IOUtils.closeQuietly(src);
|
||||
}
|
||||
}
|
||||
throws IOException {
|
||||
preserveTimeIfPossible(f);
|
||||
final InputStream src = f.getInputStream();
|
||||
try {
|
||||
engine.sendMessage("C0" + getPermString(f) + " " + f.length() + " " + f.getName());
|
||||
engine.transferToRemote(f, src);
|
||||
engine.signal("Transfer done");
|
||||
engine.check("Remote agrees transfer done");
|
||||
} finally {
|
||||
IOUtils.closeQuietly(src);
|
||||
}
|
||||
}
|
||||
|
||||
private void preserveTimeIfPossible(LocalFile f)
|
||||
throws IOException {
|
||||
if (modeGetter.preservesTimes())
|
||||
engine.sendMessage("T" + modeGetter.getLastModifiedTime(f) + " 0 " + modeGetter.getLastAccessTime(f) + " 0");
|
||||
}
|
||||
throws IOException {
|
||||
if (f.preservesTimes())
|
||||
engine.sendMessage("T" + f.getLastModifiedTime() + " 0 " + f.getLastAccessTime() + " 0");
|
||||
}
|
||||
|
||||
private String getPermString(LocalFile f)
|
||||
throws IOException {
|
||||
return Integer.toOctalString(modeGetter.getPermissions(f) & 07777);
|
||||
throws IOException {
|
||||
return Integer.toOctalString(f.getPermissions() & 07777);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user