blob: c3e2432738c811ed4ee39af6438d6f75bfacb928 [file] [log] [blame]
package org.eclipse.dltk.ssh.internal.core;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Vector;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.dltk.ssh.core.ISshFileHandle;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.ChannelSftp.LsEntry;
public class SshFileHandle implements ISshFileHandle,
IOutputStreamCloseListener {
private static final int CACHE_LIMIT = 1000;
private static class CacheEntry {
final SftpATTRS attrs;
final long lastAccess;
public CacheEntry(SftpATTRS attrs, long lastAccess) {
this.attrs = attrs;
this.lastAccess = lastAccess;
}
}
private static final Map<SshFileHandle, CacheEntry> attrCache = new HashMap<SshFileHandle, CacheEntry>();
private SshConnection connection = null;
private IPath path;
// private IPath linkTarget;
private SftpATTRS attrs;
private Map<String, SshFileHandle> children = new HashMap<String, SshFileHandle>();
private boolean childrenFetched = false;
public SshFileHandle(SshConnection connection, IPath path, SftpATTRS attrs) {
this.connection = connection;
this.path = path;
this.attrs = attrs;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.dltk.ssh.internal.core.ISshFileHandle#createFolder(java.lang
* .String, org.eclipse.core.runtime.IProgressMonitor)
*/
public ISshFileHandle createFolder(String newEntryName,
IProgressMonitor monitor) throws CoreException {
ISshFileHandle child = getChild(newEntryName);
if (child != null) {
child.mkdir();
fetchAttrs();
}
return child;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.internal.core.ISshFileHandle#mkdir()
*/
public void mkdir() {
connection.mkdir(path);
cleanAttrs();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.internal.core.ISshFileHandle#delete()
*/
public void delete() throws CoreException {
fetchAttrs();
if (attrs != null) {
connection.delete(path, attrs.isDir());
cleanAttrs();
}
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.internal.core.ISshFileHandle#exists()
*/
public boolean exists() {
fetchAttrs();
return attrs != null;
}
private void fetchAttrs() {
fetchAttrs(false);
}
private void cleanAttrs() {
attrs = null;
synchronized (attrCache) {
attrCache.remove(this);
}
}
private void fetchAttrs(boolean clean) {
if (attrs == null || clean) {
attrs = fetchCacheAttrs(clean);
}
if (attrs != null && attrs.isLink()) {
attrs = fetchCacheAttrs(true);
// this.linkTarget = connection.getResolvedPath(path);
}
}
private SftpATTRS fetchCacheAttrs(boolean clean) {
long c = 0;
synchronized (attrCache) {
if (attrCache.size() > CACHE_LIMIT) {
attrCache.clear();
} else if (!clean) {
final CacheEntry entry = attrCache.get(this);
if (entry != null) {
c = System.currentTimeMillis();
if ((c - entry.lastAccess) < 1000 * 10) {
return entry.attrs;
}
}
}
}
SftpATTRS attrs = connection.getAttrs(path);
if (c == 0) {
c = System.currentTimeMillis();
}
synchronized (attrCache) {
attrCache.put(this, new CacheEntry(attrs, c));
}
return attrs;
}
public synchronized ISshFileHandle getChild(String newEntryName) {
if (children.containsKey(newEntryName)) {
return children.get(newEntryName);
}
ISshFileHandle child = new SshFileHandle(connection, path
.append(newEntryName), null);
return child;
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.dltk.ssh.internal.core.ISshFileHandle#getChildren(org.eclipse
* .core.runtime.IProgressMonitor)
*/
public synchronized ISshFileHandle[] getChildren(IProgressMonitor monitor)
throws CoreException {
if (!childrenFetched) {
// Fetch all child handles
fetchChildren();
}
return children.values().toArray(new SshFileHandle[children.size()]);
}
private void fetchChildren() {
Vector<LsEntry> list = connection.list(path);
if (list != null) {
children.clear();
long c = System.currentTimeMillis();
for (LsEntry entry : list) {
String filename = entry.getFilename();
if (filename.equals(".") || filename.equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$
continue;
}
final SftpATTRS childAttrs = entry.getAttrs();
final IPath childPath;
if (filename.indexOf(IPath.DEVICE_SEPARATOR) == -1) {
childPath = path.append(filename);
} else {
// this way DEVICE_SEPARATOR is kept in path segment
childPath = path.append(new Path(null, filename));
}
SshFileHandle childHandle = new SshFileHandle(connection,
childPath, childAttrs);
synchronized (attrCache) {
attrCache.put(childHandle, new CacheEntry(childAttrs, c));
}
children.put(filename, childHandle);
}
childrenFetched = true;
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.dltk.ssh.internal.core.ISshFileHandle#getInputStream(org.
* eclipse.core.runtime.IProgressMonitor)
*/
public InputStream getInputStream(IProgressMonitor monitor)
throws CoreException {
// fetchAttrs();
// if (attrs != null) {
// IPath current = this.path;
// if (attrs.isLink() && linkTarget != null) {
// current = linkTarget;
// }
final InputStream stream = connection.get(this.path);
// TODO throw/wrap original exception?
return stream;
// }
// return null;
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.internal.core.ISshFileHandle#getName()
*/
public String getName() {
return path.lastSegment();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.core.ISshFileHandle#getPath()
*/
public IPath getPath() {
return path;
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return path.toString();
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.dltk.ssh.internal.core.ISshFileHandle#getOutputStream(org
* .eclipse.core.runtime.IProgressMonitor)
*/
public OutputStream getOutputStream(IProgressMonitor monitor)
throws CoreException {
final OutputStream stream = connection.put(this.path, this);
return stream;
}
public void streamClosed() {
cleanAttrs();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.internal.core.ISshFileHandle#isDirectory()
*/
public boolean isDirectory() {
fetchAttrs();
if (attrs != null) {
return attrs.isDir();
} else {
// IStatus status = new Status(IStatus.ERROR, "blah",
// "Failed to retrive file information:" + path);
// throw new CoreException(status);
return false;
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.dltk.ssh.internal.core.ISshFileHandle#lastModificationTime()
*/
public long lastModificationTime() {
fetchAttrs();
if (attrs != null) {
return attrs.getMTime() * 1000L;
} else {
// IStatus status = new Status(IStatus.ERROR, "blah",
// "Failed to retrive file information:" + path);
// throw new CoreException(status);
return 0;
}
}
/*
* (non-Javadoc)
*
* @see
* org.eclipse.dltk.ssh.internal.core.ISshFileHandle#setLastModified(long,
* org.eclipse.core.runtime.IProgressMonitor)
*/
public void setLastModified(long timestamp, IProgressMonitor monitor)
throws CoreException {
connection.setLastModified(path, timestamp);
cleanAttrs();
}
/*
* (non-Javadoc)
*
* @see org.eclipse.dltk.ssh.internal.core.ISshFileHandle#getSize()
*/
public long getSize() {
fetchAttrs();
if (attrs != null) {
return attrs.getSize();
}
return 0;
}
public boolean isSymlink() {
final SftpATTRS attrs = connection.getLAttrs(path);
return attrs != null && attrs.isLink();
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result
+ ((connection == null) ? 0 : connection.hashCode());
result = prime * result + ((path == null) ? 0 : path.hashCode());
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
SshFileHandle other = (SshFileHandle) obj;
if (connection == null) {
if (other.connection != null)
return false;
} else if (!connection.equals(other.connection))
return false;
if (path == null) {
if (other.path != null)
return false;
} else if (!path.equals(other.path))
return false;
return true;
}
public String readLink() {
return connection.readLink(path);
}
public void move(IPath destination) throws CoreException {
connection.move(path, destination);
}
}