org.jwall.apache.httpd.service.SshFileSystem Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of apache-config Show documentation
Show all versions of apache-config Show documentation
A Java library for reading Apache httpd configuration files
The newest version!
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright (C) 2010-2014 Christian Bockermann
*
* This file is part of the jwall.org apache-config library. The apache-config library is
* a parsing library to handle Apache HTTPD configuration files.
*
* More information and documentation for the jwall-tools can be found at
*
* http://www.jwall.org/apache-config
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 3 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along with this
* program; if not, see .
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
package org.jwall.apache.httpd.service;
import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.URL;
import java.nio.ByteBuffer;
import java.util.Vector;
import org.jwall.apache.httpd.MD5;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ch.ethz.ssh2.Connection;
import ch.ethz.ssh2.SCPClient;
import ch.ethz.ssh2.SFTPException;
import ch.ethz.ssh2.SFTPv3Client;
import ch.ethz.ssh2.SFTPv3DirectoryEntry;
import ch.ethz.ssh2.SFTPv3FileAttributes;
import ch.ethz.ssh2.SFTPv3FileHandle;
import ch.ethz.ssh2.Session;
/**
*
* This class implements a simple file system wrapper which accesses files on
* a remote machine via the SSH protocol. All transfers are thus being encrypted.
*
*
* TODO: - Implement versioning file system?
* - Add support for Pubkey authentication
*
*
* @author Christian Bockermann <[email protected]>
*
*/
public class SshFileSystem extends AbstractFileSystem {
static Logger log = LoggerFactory.getLogger( SshFileSystem.class );
String host;
String user;
String pass;
Connection c;
SFTPv3Client sftp;
String md5sum = null;
/**
* Creates a new instance of this class which will establish a connection to the
* given host using the specified username and password.
*
* @param host
* @param username
* @param password
* @throws Exception If the connection failed (no connection, wrong authentication, ...)
*/
public SshFileSystem( String host, String username, String password ) throws Exception {
this.host = host;
this.user = username;
this.pass = password;
c = new Connection( host );
log.info( " connecting to {}", host );
c.connect();
log.info( " authenticating with user '{}', password '{}'", user, "*****" );
c.authenticateWithPassword( user, pass );
init( c );
}
public SshFileSystem( Connection c ) throws Exception {
if( !c.isAuthenticationComplete() )
throw new Exception( "Connection not fully authenticated!" );
host = c.getHostname();
init( c );
}
private void init( Connection c ) throws Exception {
sftp = new SFTPv3Client( c );
try {
Session s = c.openSession();
s.execCommand( "which md5sum" );
BufferedReader r = new BufferedReader( new InputStreamReader( s.getStdout() ) );
md5sum = r.readLine();
r.close();
s.close();
log.info( "md5sum: {}", md5sum );
} catch (Exception e) {
e.printStackTrace();
md5sum = null;
}
}
private SFTPv3FileHandle getHandle( File file ){
try {
if( !this.exists( file ) )
return null;
SFTPv3FileAttributes stats = sftp.stat( file.getAbsolutePath() );
if( stats == null )
return null;
return sftp.openFileRO( file.getAbsolutePath() );
} catch (Exception e) {
log.error( "Cannot open file-handle: " + e.getMessage(), e );
//if( log.isDebugEnabled() )
// e.printStackTrace();
return null;
}
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#canRead(java.io.File)
*/
public boolean canRead(File file) {
// TODO: This is currently a fake implementation and needs to
// be re-implemented to match the file permissions against
// this connection's user-id
SFTPv3FileHandle handle = getHandle( file );
if( handle == null )
return false;
try {
SFTPv3FileAttributes att = sftp.fstat( handle );
return att.isRegularFile() || att.isDirectory();
} catch (Exception e) {
}
return false;
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#exists(java.io.File)
*/
public boolean exists(File file) {
try {
for( Object o : sftp.ls( file.getParent() ) ){
SFTPv3DirectoryEntry de = (SFTPv3DirectoryEntry) o;
if( de.filename.equals( file.getName() ) )
return true;
}
return false;
} catch (Exception e) {
return false;
}
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#isDirectory(java.io.File)
*/
public boolean isDirectory(File file) {
try {
SFTPv3FileHandle handle = getHandle( file );
if( handle == null )
return false;
SFTPv3FileAttributes att = sftp.fstat( handle );
return att.isDirectory();
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#listFiles(java.io.File)
*/
public File[] listFiles(File directory) {
if( ! isDirectory( directory ) )
return new File[0];
try {
Vector> vec = sftp.ls( directory.getAbsolutePath() );
File[] results = new File[ vec.size() ];
int i = 0;
for( Object o : vec ){
SFTPv3DirectoryEntry de = (SFTPv3DirectoryEntry) o;
results[i] = new File( directory + "/" + de.filename );
log.debug( "file[{}] = {}", i, results[i] );
i++;
}
return results;
} catch (Exception e) {
e.printStackTrace();
}
return new File[0];
}
public boolean isSymlink( File file ){
try {
for( Object o : sftp.ls( file.getParent() ) ){
SFTPv3DirectoryEntry de = (SFTPv3DirectoryEntry) o;
if( de.filename.equals( file.getName() ) ){
log.debug( "Checking {}", de.filename );
return de.longEntry.toLowerCase().startsWith( "l" );
}
}
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#openInputStream(java.io.File)
*/
public InputStream openInputStream( File f ) throws IOException {
return new ByteArrayInputStream( this.get( f ) );
}
public String getAbsolutePath(File file) {
String fp = file.getAbsolutePath();
try {
fp = sftp.canonicalPath( file.getAbsolutePath() );
} catch (IOException e) {
fp = file.getAbsolutePath();
}
if( ! fp.startsWith( "/" ) )
fp = "/" + fp;
return "sftp://" + user + ":*****@" + host + ":" + fp;
}
public long copy(File file, OutputStream out) throws IOException {
if( isSymlink( file ) ){
throw new IOException( "Cannot copy symlink to output-stream!" );
}
InputStream in = this.openInputStream( file );
byte[] buf = new byte[ 16 * 1024 ];
long total = 0L;
int read = in.read( buf );
while( read > 0 ){
out.write( buf, 0, read );
total += read;
read = in.read( buf );
}
return total;
}
public URL getURL(File file) {
try {
return new URL( getAbsolutePath( file ) );
} catch (Exception e) {
e.getMessage();
return null;
}
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#openOutputStream(java.io.File)
*/
public OutputStream openOutputStream(File file) throws IOException {
return new SshOutputStream( file, sftp, 1024 );
}
public byte[] get(File file) throws IOException {
log.info( "Retrieving file {}", file );
SCPClient scp = c.createSCPClient();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
scp.get( file.getPath(), baos );
baos.close();
return baos.toByteArray();
}
public void put(File file, byte[] content) throws IOException {
log.debug( "Sending file {}", file );
SCPClient scp = c.createSCPClient();
String parentDir = file.getParentFile().getAbsolutePath();
log.debug( "invoking 'mkdir -p {}'", parentDir );
Session s = c.openSession();
s.execCommand( "mkdir -p " + parentDir );
s.close();
scp.put( content, file.getName(), file.getParentFile().getAbsolutePath() );
}
public class SshInputStream extends InputStream {
Logger log = LoggerFactory.getLogger( SshInputStream.class );
File file;
SFTPv3FileHandle fh;
SFTPv3Client sftp;
long offset = 0L;
Long read = 0L;
Long size = 0L;
ByteBuffer buffer;
int bufferSize = 1024;
int bufferFilled = -1;
public SshInputStream( File file, SFTPv3Client sftp, int bufferSize ) throws IOException {
this.file = file;
this.sftp = sftp;
fh = sftp.openFileRO( file.getAbsolutePath() );
SFTPv3FileAttributes fattr = sftp.fstat( fh );
size = fattr.size;
buffer = ByteBuffer.allocate( bufferSize );
this.bufferSize = bufferSize;
}
public void fillBuffer() throws IOException {
buffer.clear();
int bytesRead = sftp.read( fh, offset, buffer.array(), buffer.position(), buffer.remaining() );
if( bufferFilled < 0 )
bufferFilled = bytesRead;
else
bufferFilled += bytesRead;
//buffer.flip();
buffer.limit( bytesRead );
log.debug( "Filled buffer with {} bytes, buffer has {} bytes remaining", bytesRead, buffer.remaining() );
}
@Override
public int read() throws IOException {
if( fh == null )
throw new IOException( "No filehandle available - stream already closed?" );
if( offset >= size )
return -1;
if( offset >= bufferFilled )
fillBuffer();
if( offset >= bufferFilled || offset >= size )
return -1;
int data = buffer.get();
offset++;
return data;
}
/**
* @see java.io.InputStream#close()
*/
@Override
public void close() throws IOException {
super.close();
this.fh = null;
}
}
public class SshOutputStream extends OutputStream {
Logger log = LoggerFactory.getLogger( SshOutputStream.class );
File file;
SFTPv3FileHandle fh;
SFTPv3Client sftp;
long offset = 0L;
Long read = 0L;
Long size = 0L;
ByteBuffer buffer;
int bufferSize = 1024;
int bufferFilled = -1;
public SshOutputStream( File file, SFTPv3Client sftpClient, int bufferSize ) throws IOException {
this.file = file;
this.sftp = sftpClient;
SFTPv3FileAttributes fattr = null;
try {
fattr = sftp.lstat( file.getAbsolutePath() );
if( fattr.isDirectory() )
throw new IOException( "Cannot open directory '" + file.getAbsolutePath() + "' for writing!" );
} catch (SFTPException se ){
if( se.getMessage().indexOf( "No such file") >= 0 ){
fh = sftp.createFile( file.getAbsolutePath() );
} else {
throw se;
}
}
if( fattr != null && fattr.isDirectory() )
throw new IOException( "Cannot open directory '" + file.getAbsolutePath() + "' for writing!" );
if( fattr == null || !fattr.isRegularFile() ){
log.debug( "File does not exist, creating empty file..." );
/*
if( file.getParentFile() != null ){
log.info( "Creating parent directory..." );
sftp.mkdir( file.getParent(), 0x755 );
}
*/
fh = sftp.createFile( file.getAbsolutePath() );
//fh = sftp.openFileRW( file.getAbsolutePath() );
} else {
log.debug( "Opening existing file {}", file );
fh = sftp.openFileRW( file.getAbsolutePath() );
}
size = fattr.size;
this.bufferSize = bufferSize;
this.buffer = ByteBuffer.allocate( bufferSize );
}
/**
* @see java.io.OutputStream#write(int)
*/
@Override
public void write(int arg0) throws IOException {
if( fh == null )
throw new IOException( "No filehandle available - stream already closed?" );
if( buffer.remaining() == 0 ){
log.debug( "Buffer full, auto-flushing stream..." );
flush();
}
log.debug( "adding byte to buffer: {}", (char) arg0 );
buffer.put( (byte) arg0 );
}
/**
* @see java.io.OutputStream#close()
*/
@Override
public void close() throws IOException {
if( fh == null )
throw new IOException( "No filehandle available - stream already closed?" );
flush();
log.debug( "Closing file-handle" );
sftp.closeFile( fh );
fh = null;
}
/**
* @see java.io.OutputStream#flush()
*/
@Override
public void flush() throws IOException {
if( fh == null )
throw new IOException( "No filehandle available - stream already closed?" );
if( buffer.position() == 0 ){
log.debug( "buffer empty, not flushing" );
return;
}
int out = buffer.position();
StringBuffer s = new StringBuffer();
for( int i = 0; i < out; i++ ){
s.append( (char) buffer.array()[i] );
}
log.debug( "Buffer content:\n{}", s );
log.debug( "Writing {} bytes to ssh-conncection", out );
sftp.write( fh, offset, buffer.array(), 0, out );
log.debug( "Clearing buffer..." );
buffer.clear();
offset += out;
}
}
public void createSymlink( String destination, File name) throws IOException {
log.debug( "Creating symlink {} -> {}", name.getAbsolutePath(), destination );
sftp.createSymlink( name.getAbsolutePath(), destination );
}
public boolean createDirectory(File file) throws IOException {
sftp.mkdir( file.getAbsolutePath(), 0x755 );
return isDirectory( file );
}
public boolean delete(File file) throws IOException {
sftp.rm( file.getAbsolutePath() );
return !this.exists( file );
}
public String getRealPath( File f ) throws IOException {
File file = f;
if( isSymlink( f ) ){
for( Object o : sftp.ls( f.getParent() ) ){
SFTPv3DirectoryEntry de = (SFTPv3DirectoryEntry) o;
log.debug( "Directory entry: {}", de.longEntry );
}
log.debug( "File {} denotes a symlink!", file );
String realFile = sftp.readLink( file.getAbsolutePath() );
if( realFile.startsWith( "/" ) )
file = new File( realFile );
else {
file = new File( f.getParent() + "/" + realFile );
}
} else {
file = f;
}
String path = sftp.canonicalPath( file.getAbsolutePath() );
log.debug( " real path is {}", path );
return path;
}
public String readSymlink(File symlink) {
try {
log.debug( "File {} denotes a symlink!", symlink );
return sftp.readLink( symlink.getPath() );
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public File resolveSymlink( File symlink ){
if( !isSymlink( symlink ) )
return symlink;
try {
log.debug( "File {} denotes a symlink!", symlink );
String realFile = sftp.readLink( symlink.getPath() );
if( realFile.startsWith( "/" ) )
symlink = new File( realFile );
else {
symlink= new File( symlink.getParent() + "/" + realFile );
}
return new File( sftp.canonicalPath( symlink.getPath() ) );
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
/**
* @see org.jwall.apache.httpd.service.FileSystem#md5(java.io.File)
*/
public String md5(File file) throws IOException {
if( md5sum != null ){
Session s = c.openSession();
s.execCommand( md5sum + " " + file.getPath() );
BufferedReader r = new BufferedReader( new InputStreamReader( s.getStdout() ) );
String cksm = r.readLine();
r.close();
s.close();
if( cksm == null )
throw new IOException( "Failed to compute md5sum!" );
log.debug( "md5sum:\n{}", cksm );
int idx = cksm.indexOf( " " );
if( idx > 0 )
return cksm.substring( 0, idx );
else
return cksm;
} else {
ByteArrayOutputStream out = new ByteArrayOutputStream();
InputStream fis = openInputStream( file );
byte[] buf = new byte[ 16 * 1024 ];
int read = fis.read( buf );
while( read > 0 ){
out.write( buf, 0, read );
read = fis.read( buf );
}
out.close();
return MD5.md5( out.toByteArray() );
}
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy