/***************************************************************************** * Copyright (c) 2006, 2008 g-Eclipse Consortium * 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 * * Initial development of the original code was made for the * g-Eclipse project founded by European Union * project number: FP6-IST-034327 http://www.geclipse.eu/ * * Contributors: * Christof Klausecker GUP, JKU - initial API and implementation *****************************************************************************/ package eu.geclipse.efs.sftp; import java.io.InputStream; import java.io.OutputStream; import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.HashMap; 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.Path; import com.jcraft.jsch.ChannelSftp; import com.jcraft.jsch.SftpATTRS; import com.jcraft.jsch.SftpException; import com.jcraft.jsch.ChannelSftp.LsEntry; import eu.geclipse.efs.sftp.internal.CloseInputStream; import eu.geclipse.efs.sftp.internal.CloseOutputStream; import eu.geclipse.efs.sftp.internal.ConnectionKey; import eu.geclipse.efs.sftp.internal.ConnectionManager; import eu.geclipse.efs.sftp.internal.SFTPConnection; /** * SFTP EFS FileStore implementation */ public class SFTPFileStore extends FileStore { private URI uri; private ConnectionKey connectionKey; private SFTPFileStore parent; private IPath path; private FileInfo myFileInfo; private HashMap<String, FileStore> children; private ArrayList<String> childNames; private ArrayList<IFileInfo> childInfos; /** * Creates a new SFTP filestore * * @param uri */ protected SFTPFileStore( final URI uri ) { this.connectionKey = new ConnectionKey( uri ); this.uri = uri; this.parent = null; this.path = new Path( uri.getPath() ); this.children = new HashMap<String, FileStore>(); this.childNames = new ArrayList<String>(); this.childInfos = new ArrayList<IFileInfo>(); String name = new Path( uri.getPath() ).lastSegment(); if( name != null && name.length() > 0 ) { this.myFileInfo = new FileInfo( name ); } else { this.myFileInfo = new FileInfo(); } } private SFTPFileStore( final SFTPFileStore parent, final FileInfo fileInfo ) { this.connectionKey = parent.connectionKey; this.uri = parent.uri; this.parent = parent; this.path = parent.path.append( fileInfo.getName() ); this.children = new HashMap<String, FileStore>(); this.childNames = new ArrayList<String>(); this.childInfos = new ArrayList<IFileInfo>(); this.myFileInfo = fileInfo; try { this.uri = new URI( this.uri.getScheme(), this.uri.getUserInfo(), this.uri.getHost(), this.uri.getPort(), this.path.toString(), this.uri.getQuery(), this.uri.getFragment() ); } catch( URISyntaxException uriSyntaxException ) { Activator.logException( uriSyntaxException ); } } @SuppressWarnings("unchecked") private void update() throws CoreException { SFTPConnection connection = ConnectionManager.getInstance() .acquireConnection( this.connectionKey ); ChannelSftp channel = connection.getChannel(); if( this.uri.getPath().length() == 0 ) { try { this.uri = new URI( this.uri.getScheme(), this.uri.getUserInfo(), this.uri.getHost(), this.uri.getPort(), channel.getHome(), this.uri.getQuery(), this.uri.getFragment() ); this.path = new Path( this.uri.getPath() ); } catch( URISyntaxException uriSyntaxException ) { Activator.logException( uriSyntaxException ); } // necessary for ganymede catch( SftpException sftpException ) { Activator.logException( sftpException ); } } try { String remotePath = this.path.toString(); if( remotePath.length() == 0 ) { remotePath = "/"; //$NON-NLS-1$ } Vector<LsEntry> vector = channel.ls( remotePath ); for( LsEntry lsEntry : vector ) { String filename = lsEntry.getFilename(); if( !"..".equals( filename ) && filename.indexOf( ':' ) == -1 ) { //$NON-NLS-1$ SftpATTRS attributes = lsEntry.getAttrs(); FileInfo fileInfo = new FileInfo( filename ); fileInfo.setLength( attributes.getSize() ); fileInfo.setDirectory( attributes.isDir() ); fileInfo.setExists( true ); fileInfo.setLastModified( ( long )attributes.getMTime() * 1000 ); // TODO think about a ways to get attribute fileInfo.setAttribute( EFS.ATTRIBUTE_READ_ONLY, false ); if( ".".equals( filename ) || vector.size() == 1 ) { //$NON-NLS-1$ if( ".".equals( filename ) ) { //$NON-NLS-1$ fileInfo.setName( remotePath ); } else { fileInfo.setName( filename ); } if( this.myFileInfo == null || this.myFileInfo.getLastModified() != fileInfo.getLastModified() ) { this.myFileInfo = fileInfo; } } else { this.children.put( filename, new SFTPFileStore( this, fileInfo ) ); this.childNames.add( filename ); this.childInfos.add( fileInfo ); } } } } catch( SftpException sftpException ) { this.myFileInfo = new FileInfo( this.path.lastSegment() ); this.myFileInfo.setExists( false ); this.myFileInfo.setAttribute( EFS.ATTRIBUTE_READ_ONLY, false ); if( sftpException.id != 2 ) { Activator.logException( sftpException ); } } finally { connection.unlock(); } } @Override public String getName() { return this.myFileInfo.getName(); } @Override public IFileStore getParent() { return this.parent; } @Override public IFileStore getChild( final String name ) { IFileStore child = this.children.get( name ); if( child == null ) { FileInfo childFileInfo = new FileInfo( name ); childFileInfo.setExists( false ); child = new SFTPFileStore( this, childFileInfo ); } return child; } @Override public void putInfo( final IFileInfo info, final int options, final IProgressMonitor monitor ) throws CoreException { // empty } @Override public IFileInfo fetchInfo() { try { update(); } catch( CoreException e ) { // empty } return this.myFileInfo; } @Override public IFileInfo fetchInfo( final int options, final IProgressMonitor monitor ) throws CoreException { update(); return this.myFileInfo; } @Override public void delete( final int options, final IProgressMonitor monitor ) throws CoreException { SFTPConnection connection = ConnectionManager.getInstance() .acquireConnection( this.connectionKey ); ChannelSftp channel = connection.getChannel(); update(); try { if( this.myFileInfo.isDirectory() ) { if( this.children.size() != 0 ) { for( FileStore filestore : this.children.values() ) { filestore.delete( 0, monitor ); } } channel.rmdir( this.path.toString() ); } else { channel.rm( this.path.toString() ); // this.parent.update(); } } catch( SftpException sftpException ) { Activator.logException( sftpException ); } finally { this.myFileInfo.setExists( false ); connection.unlock(); } } @Override public InputStream openInputStream( final int options, final IProgressMonitor monitor ) throws CoreException { SFTPConnection connection = ConnectionManager.getInstance() .acquireConnection( this.connectionKey ); ChannelSftp channel = connection.getChannel(); InputStream inputStream = null; try { inputStream = new CloseInputStream( channel.get( this.path.toString() ), connection ); } catch( SftpException sftpException ) { Activator.logException( sftpException ); connection.unlock(); } return inputStream; } @Override public OutputStream openOutputStream( final int options, final IProgressMonitor monitor ) throws CoreException { SFTPConnection connection = ConnectionManager.getInstance() .acquireConnection( this.connectionKey ); ChannelSftp channel = connection.getChannel(); OutputStream outputStream = null; try { OutputStream o = channel.put( this.path.toString(), ChannelSftp.OVERWRITE ); outputStream = new CloseOutputStream( o, connection ); } catch( SftpException sftpException ) { Activator.logException( sftpException ); connection.unlock(); } return outputStream; } @Override public IFileStore mkdir( final int options, final IProgressMonitor monitor ) throws CoreException { SFTPConnection connection = ConnectionManager.getInstance().acquireConnection( this.connectionKey ); ChannelSftp channel = connection.getChannel(); try { channel.mkdir( this.path.toString() ); this.myFileInfo.setExists( true ); this.myFileInfo.setDirectory( true ); } catch( SftpException sftpException ) { // Activator.logException( sftpException ); // connection.unlock(); } return this; } @Override public String[] childNames( final int options, final IProgressMonitor monitor ) throws CoreException { update(); return this.childNames.toArray( new String[ 0 ] ); } @Override public IFileInfo[] childInfos( final int options, final IProgressMonitor monitor ) throws CoreException { update(); return this.childInfos.toArray( new IFileInfo[ 0 ] ); } @Override public IFileStore[] childStores( final int options, final IProgressMonitor monitor ) throws CoreException { update(); return this.children.entrySet().toArray( new IFileStore[ 0 ] ); } @Override public URI toURI() { return this.uri; } @Override public void move( final IFileStore destination, final int options, final IProgressMonitor monitor ) throws CoreException { // TODO implement to improve performance super.move( destination, options, monitor ); } @Override protected void copyFile( final IFileInfo sourceInfo, final IFileStore destination, final int options, final IProgressMonitor monitor ) throws CoreException { // TODO implement to improve performance super.copyFile( sourceInfo, destination, options, monitor ); } @Override protected void copyDirectory( final IFileInfo sourceInfo, final IFileStore destination, final int options, final IProgressMonitor monitor ) throws CoreException { // TODO implement to improve performance super.copyDirectory( sourceInfo, destination, options, monitor ); } @Override public void copy( final IFileStore destination, final int options, final IProgressMonitor monitor ) throws CoreException { // TODO implement to improve performance super.copy( destination, options, monitor ); } }