/*******************************************************************************
* Copyright (c) 2012 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.linuxtools.internal.ssh.proxy;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URI;
import java.net.URISyntaxException;
import java.text.MessageFormat;
import java.util.LinkedList;
import java.util.Vector;
import org.eclipse.core.filesystem.EFS;
import org.eclipse.core.filesystem.IFileInfo;
import org.eclipse.core.filesystem.IFileStore;
import org.eclipse.core.filesystem.provider.FileInfo;
import org.eclipse.core.filesystem.provider.FileStore;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.eclipse.core.runtime.Path;
import org.eclipse.core.runtime.Status;
import com.jcraft.jsch.ChannelSftp;
import com.jcraft.jsch.SftpATTRS;
import com.jcraft.jsch.SftpException;
public class SSHFileStore extends FileStore {
private URI uri;
private Path path;
private SSHFileProxy proxy;
private static final int USER_READ = 256;
private static final int USER_WRITE = 128;
private static final int USER_EXEC = 64;
private static final int GROUP_READ = 32;
private static final int GROUP_WRITE = 16;
private static final int GROUP_EXEC = 8;
private static final int OTHER_READ = 4;
private static final int OTHER_WRITE = 2;
private static final int OTHER_EXEC = 1;
public SSHFileStore(URI uri, SSHFileProxy proxy) {
this.uri = uri;
this.proxy = proxy;
this.path = new Path(uri.getPath());
}
@Override
public String[] childNames(int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask(Messages.SSHFileStore_childNamesMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
Vector<?> v = channel.ls(uri.getPath());
monitor.worked(50);
LinkedList<String> childs = new LinkedList<>();
boolean isDir = false;
for (int i=0; i < v.size(); i++) {
ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) v.get(i);
if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$
childs.add(entry.getFilename());
} else {
isDir = true;
}
}
if (!isDir) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
MessageFormat.format(Messages.SSHFileStore_childNamesFailedDirectory, getName())));
}
monitor.worked(100);
monitor.done();
return childs.toArray(new String[0]);
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_childNamesFailed + e.getMessage()));
}
}
@Override
public IFileInfo[] childInfos(int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask(Messages.SSHFileStore_childInfoMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
Vector<?> v = channel.ls(uri.getPath());
monitor.worked(50);
LinkedList<IFileInfo> childs = new LinkedList<>();
boolean isDir = false;
for (int i=0; i < v.size(); i++) {
ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) v.get(i);
if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) { //$NON-NLS-1$ //$NON-NLS-2$
childs.add(createFileInfo(entry.getAttrs()));
} else {
isDir = true;
}
}
if (!isDir) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
MessageFormat.format(Messages.SSHFileStore_childInfoFailedDirectory, getName())));
}
monitor.worked(100);
monitor.done();
return childs.toArray(new IFileInfo[0]);
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_childInfoFailed + e.getMessage()));
}
}
@Override
public IFileInfo fetchInfo() {
try {
return fetchInfo(EFS.NONE, new NullProgressMonitor());
} catch (CoreException e) {
return null;
}
}
@Override
public IFileStore[] childStores(int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null)
monitor = new NullProgressMonitor();
try {
monitor.beginTask(Messages.SSHFileStore_childStoresMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
Vector<?> v = channel.ls(uri.getPath());
monitor.worked(50);
LinkedList<IFileStore> childs = new LinkedList<>();
boolean isDir = false;
for (int i=0; i < v.size(); i++) {
ChannelSftp.LsEntry entry = (ChannelSftp.LsEntry) v.get(i);
if (!entry.getFilename().equals(".") && !entry.getFilename().equals("..")) //$NON-NLS-1$ //$NON-NLS-2$
childs.add(createFileStore(path.append(entry.getFilename()).toString()));
else
isDir = true;
}
if (!isDir)
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID,
MessageFormat.format(Messages.SSHFileStore_childStoresFailedDirectory, getName())));
monitor.worked(100);
monitor.done();
return childs.toArray(new IFileStore[0]);
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_childStoresFailed + e.getMessage()));
}
}
@Override
public void delete(int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null)
monitor = new NullProgressMonitor();
try {
monitor.beginTask(Messages.SSHFileStore_rmMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
if (channel.lstat(uri.getPath()).isDir())
channel.rmdir(uri.getPath());
else
channel.rm(uri.getPath());
monitor.worked(100);
monitor.done();
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_rmFailed + e.getMessage()));
}
}
@Override
public IFileInfo fetchInfo(int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null)
monitor = new NullProgressMonitor();
try {
monitor.beginTask(Messages.SSHFileStore_attrMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
SftpATTRS attrs = channel.stat(uri.getPath());
monitor.worked(100);
monitor.done();
return createFileInfo(attrs);
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_attrFailed + e.getMessage()));
}
}
@Override
public IFileStore getChild(String name) {
String strPath = path.append(name).toString();
return createFileStore(strPath);
}
@Override
public String getName() {
String name = path.lastSegment();
if (name == null)
name = ""; //$NON-NLS-1$
return name;
}
@Override
public IFileStore getParent() {
if (path.isRoot())
return null;
String strPath = path.removeLastSegments(1).toString();
return createFileStore(strPath);
}
@Override
public IFileStore mkdir(int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null)
monitor = new NullProgressMonitor();
monitor.beginTask(Messages.SSHFileStore_mkdirMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
IPath new_path = Path.ROOT;
if ((options & EFS.SHALLOW) == 0) {
for (String segment : path.segments()) {
new_path = new_path.append(segment);
try {
channel.stat(new_path.toString());
} catch (SftpException e) {
//Path doesn't exist
createDir(channel, new_path.toString());
}
}
} else
createDir(channel, uri.getPath());
monitor.worked(100);
monitor.done();
return this;
}
private void createDir(ChannelSftp channel, String dir) throws CoreException {
try {
channel.mkdir(dir);
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_mkdirFailed + e.getMessage()));
}
}
@Override
public InputStream openInputStream(int options, IProgressMonitor monitor)
throws CoreException {
try {
ChannelSftp channel = proxy.getChannelSftp();
return channel.get(uri.getPath(), new ProgressMonitor(monitor, Messages.SSHFileStore_getInputStreamMonitor));
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_getInputStreamFailed + e.getMessage()));
}
}
@Override
public OutputStream openOutputStream(int options, IProgressMonitor monitor)
throws CoreException {
try {
ChannelSftp channel = proxy.getChannelSftp();
int mode = ChannelSftp.OVERWRITE;
if ((options & EFS.APPEND) != 0)
mode = ChannelSftp.APPEND;
return channel.put(uri.getPath(), new ProgressMonitor(monitor, Messages.SSHFileStore_getOutputStreamMonitor), mode);
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_getOutputStreamFailed + e.getMessage()));
}
}
@Override
public void putInfo(IFileInfo info, int options, IProgressMonitor monitor)
throws CoreException {
if (monitor == null) {
monitor = new NullProgressMonitor();
}
try {
monitor.beginTask(Messages.SSHFileStore_putInfoMonitor, 100);
ChannelSftp channel = proxy.getChannelSftp();
monitor.worked(25);
SftpATTRS attrs = channel.stat(uri.getPath());
updateSftpATTRS(info);
channel.setStat(uri.getPath(), attrs);
monitor.worked(100);
monitor.done();
} catch (SftpException e) {
throw new CoreException(new Status(IStatus.ERROR, Activator.PLUGIN_ID, Messages.SSHFileStore_putInfoFailed + e.getMessage()));
}
}
@Override
public URI toURI() {
return this.uri;
}
private IFileStore createFileStore(String newPath) {
try {
return new SSHFileStore(new URI(uri.getScheme(), uri.getUserInfo(), uri.getHost(), uri.getPort(),
newPath, uri.getQuery(), uri.getFragment()), this.proxy);
} catch (URISyntaxException e) {
//This is not suppose to happen
return null;
}
}
private IFileInfo createFileInfo(SftpATTRS attrs) {
FileInfo f = new FileInfo();
f.setExists(true);
f.setLastModified(attrs.getMTime());
f.setLength(attrs.getSize());
f.setName(getName());
f.setDirectory(attrs.isDir());
int p = attrs.getPermissions();
if ((p & USER_READ) != 0) {
f.setAttribute(EFS.ATTRIBUTE_OWNER_READ, true);
}
if ((p & USER_WRITE) != 0) {
f.setAttribute(EFS.ATTRIBUTE_OWNER_WRITE, true);
}
if ((p & USER_EXEC) != 0) {
f.setAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE, true);
}
if ((p & GROUP_READ) != 0) {
f.setAttribute(EFS.ATTRIBUTE_GROUP_READ, true);
}
if ((p & GROUP_WRITE) != 0) {
f.setAttribute(EFS.ATTRIBUTE_GROUP_WRITE, true);
}
if ((p & GROUP_EXEC) != 0) {
f.setAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE, true);
}
if ((p & OTHER_READ) != 0) {
f.setAttribute(EFS.ATTRIBUTE_OTHER_READ, true);
}
if ((p & OTHER_WRITE) != 0) {
f.setAttribute(EFS.ATTRIBUTE_OTHER_WRITE, true);
}
if ((p & OTHER_EXEC) != 0) {
f.setAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE, true);
}
return f;
}
private void updateSftpATTRS(IFileInfo f) {
int p = 0;
if (f.getAttribute(EFS.ATTRIBUTE_OWNER_READ)) {
p = p | USER_READ;
}
if (f.getAttribute(EFS.ATTRIBUTE_OWNER_WRITE)) {
p = p | USER_WRITE;
}
if (f.getAttribute(EFS.ATTRIBUTE_OWNER_EXECUTE)) {
p = p | USER_EXEC;
}
if (f.getAttribute(EFS.ATTRIBUTE_GROUP_READ)) {
p = p | GROUP_READ;
}
if (f.getAttribute(EFS.ATTRIBUTE_GROUP_WRITE)) {
p = p | GROUP_WRITE;
}
if (f.getAttribute(EFS.ATTRIBUTE_GROUP_EXECUTE)) {
p = p | GROUP_EXEC;
}
if (f.getAttribute(EFS.ATTRIBUTE_OTHER_READ)) {
p = p | OTHER_READ;
}
if (f.getAttribute(EFS.ATTRIBUTE_OTHER_WRITE)) {
p = p | OTHER_WRITE;
}
if (f.getAttribute(EFS.ATTRIBUTE_OTHER_EXECUTE)) {
p = p | OTHER_EXEC;
}
}
}