com.mucommander.file.impl.sftp
Class SFTPFile

java.lang.Object
  extended by com.mucommander.file.AbstractFile
      extended by com.mucommander.file.impl.sftp.SFTPFile
All Implemented Interfaces:
PermissionAccesses, PermissionTypes

public class SFTPFile
extends AbstractFile

SFTPFile provides access to files located on an SFTP server.

The associated FileURL scheme is FileProtocols.SFTP. The host part of the URL designates the SFTP server. Credentials must be specified in the login and password parts as SFTP servers require a login and password. The path separator is '/'.

Here are a few examples of valid SFTP URLs: sftp://server/pathto/somefile
sftp://login:password@server/pathto/somefile

Internally, SFTPFile uses ConnectionPool to create SFTP connections as needed and allows them to be reused by SFTPFile instances located on the same server, dealing with concurrency issues. Connections are thus managed transparently and need not be manually managed.

Low-level SFTP implementation is provided by the J2SSH library distributed under the LGPL license.

Author:
Maxence Bernard
See Also:
ConnectionPool

Field Summary
static java.lang.String PRIVATE_KEY_PATH_PROPERTY_NAME
          Name of the property that holds the path to a private key.
 
Fields inherited from class com.mucommander.file.AbstractFile
DEFAULT_SEPARATOR, fileURL, IO_BUFFER_SIZE, MUST_HINT, MUST_NOT_HINT, SHOULD_HINT, SHOULD_NOT_HINT, windowsDriveRootPattern
 
Fields inherited from interface com.mucommander.file.PermissionTypes
EXECUTE_PERMISSION, READ_PERMISSION, WRITE_PERMISSION
 
Fields inherited from interface com.mucommander.file.PermissionAccesses
GROUP_ACCESS, OTHER_ACCESS, USER_ACCESS
 
Constructor Summary
SFTPFile(FileURL fileURL)
          Creates a new instance of SFTPFile and initializes the SSH/SFTP connection to the server.
 
Method Summary
 boolean canChangeDate()
          Returns true if this file's date can be changed using AbstractFile.changeDate(long).
 boolean canGetGroup()
          Returns true if this file implementation is able to return some information about file groups, not necessarily for all files or this file in particular but at least for some of them.
 boolean canGetOwner()
          Returns true if this file implementation is able to return some information about file owners, not necessarily for all files or this file in particular but at least for some of them.
 boolean canRunProcess()
          Returns true if it's possible to run processes on the underlying file system.
 boolean changeDate(long lastModified)
          Changes last modified date and returns true if date was changed successfully, false if the operation could not be completed, either because this method is not implemented for this file type, or because of insufficient permissions or a low-level I/O error.
 boolean changePermission(int access, int permission, boolean enabled)
          Changes the specified permission bit.
 boolean changePermissions(int permissions)
          Changes this file's permissions to the specified permissions int and returns true if the operation was successful, false if at least one of the file permissions could not be changed.
 ConnectionHandler createConnectionHandler(FileURL location)
           
 void delete()
          Deletes this file and this file only (does not recurse on folders).
 boolean exists()
          Implementation note: for symlinks, returns the value of the link's target.
 java.lang.String getCanonicalPath()
          Returns the canonical path to this file, resolving any symbolic links or '..' and '.' occurrences.
 PermissionBits getChangeablePermissions()
          Returns a bit mask describing the permission bits that can be changed on this file when calling AbstractFile.changePermission(int, int, boolean) and AbstractFile.changePermissions(int).
 long getDate()
          Implementation note: for symlinks, returns the date of the link's target.
 long getFreeSpace()
          Returns the free space (in bytes) on the disk/volume where this file is, -1 if this information is not available.
 java.lang.String getGroup()
          Returns information about the group this file belongs to.
 java.io.InputStream getInputStream()
          Returns an InputStream to read the contents of this file.
 java.io.InputStream getInputStream(long offset)
          Returns an InputStream to read this file's contents, starting at the specified offset (in bytes).
 java.io.OutputStream getOutputStream(boolean append)
          Returns an OuputStream to write the contents of this file, appending or overwriting the existing contents.
 java.lang.String getOwner()
          Returns information about the owner of this file.
 AbstractFile getParent()
          Returns this file's parent, null if it doesn't have one.
 FilePermissions getPermissions()
          Implementation note: for symlinks, returns the permissions of the link's target.
 RandomAccessInputStream getRandomAccessInputStream()
          Returns a RandomAccessInputStream to read the contents of this file with random access.
 RandomAccessOutputStream getRandomAccessOutputStream()
          Returns a RandomAccessOutputStream to write the contents of this file with random access.
 long getSize()
          Implementation note: for symlinks, returns the size of the link's target.
 long getTotalSpace()
          Returns the total space (in bytes) of the disk/volume where this file is, -1 if this information is not available.
 java.lang.Object getUnderlyingFileObject()
          Returns a SFTPFile.SFTPFileAttributes instance corresponding to this file.
 boolean hasRandomAccessInputStream()
          Returns true: getRandomAccessInputStream() is implemented.
 boolean hasRandomAccessOutputStream()
          Returns false: getRandomAccessOutputStream() is not implemented and throws an IOException.
 boolean isDirectory()
          Implementation note: for symlinks, returns the value of the link's target.
 boolean isSymlink()
          Implementation note: the value returned by this method will always be false if this file was created by the public constructor.
 AbstractFile[] ls()
          Returns the children files that this file contains.
 void mkdir()
          Creates this file as a directory.
 boolean moveTo(AbstractFile destFile)
          Overrides AbstractFile.moveTo(AbstractFile) to support server-to-server move if the destination file uses SFTP and is located on the same host.
 AbstractProcess runProcess(java.lang.String[] tokens)
          Creates a process executing the specified command tokens using this file as a working directory.
static void setAttributeCachingPeriod(long period)
          Sets the time period during which attributes values (e.g.
 void setParent(AbstractFile parent)
          Sets this file's parent.
 
Methods inherited from class com.mucommander.file.AbstractFile
addTrailingSeparator, calculateChecksum, calculateChecksum, calculateChecksum, changePermissions, checkCopyPrerequisites, copyRecursively, copyStream, copyTo, deleteRecursively, deleteRecursively, equals, getAbsolutePath, getAbsolutePath, getAncestor, getAncestor, getCanonicalFile, getCanonicalPath, getChild, getChildSilently, getCopyToHint, getDirectChild, getExtension, getExtension, getIcon, getIcon, getJavaNetURL, getMoveToHint, getName, getNameWithoutExtension, getParentArchive, getParentSilently, getPermissionsString, getRoot, getSeparator, getTopAncestor, getURL, hasAncestor, hasAncestor, hashCode, importPermissions, importPermissions, isBrowsable, isHidden, isParentOf, isRoot, ls, ls, mkdir, mkdirs, mkfile, mkfile, removeTrailingSeparator, toString
 
Methods inherited from class java.lang.Object
clone, finalize, getClass, notify, notifyAll, wait, wait, wait
 

Field Detail

PRIVATE_KEY_PATH_PROPERTY_NAME

public static final java.lang.String PRIVATE_KEY_PATH_PROPERTY_NAME
Name of the property that holds the path to a private key. This property is optional; if it is set, private key authentication is used.

See Also:
Constant Field Values
Constructor Detail

SFTPFile

public SFTPFile(FileURL fileURL)
         throws java.io.IOException
Creates a new instance of SFTPFile and initializes the SSH/SFTP connection to the server.

Throws:
java.io.IOException
Method Detail

setAttributeCachingPeriod

public static void setAttributeCachingPeriod(long period)
Sets the time period during which attributes values (e.g. isDirectory, last modified, ...) are cached. The higher this value, the lower the number of network requests but also the longer it takes before those attributes can be refreshed. A value of 0 disables attributes caching.

This class ensures that the attributes changed remotely by one of its methods are always updated locally, even with attributes caching enabled. To illustrate, after a call to mkdir(), isDirectory() will return true, even if the attributes haven't been refreshed. The attributes will however not be consistent if they have been changed by another SFTPFile or by another process, and will remain inconsistent for up to period milliseconds.

Parameters:
period - time period during which attributes values are cached, in milliseconds. 0 disables attributes caching.

createConnectionHandler

public ConnectionHandler createConnectionHandler(FileURL location)

isSymlink

public boolean isSymlink()
Implementation note: the value returned by this method will always be false if this file was created by the public constructor. If this file was created by the private constructor (by ls(), the value will be accurate (true if this file is a symlink) but will never get updated. See SFTPFile.SFTPFileAttributes for more information.

Specified by:
isSymlink in class AbstractFile
Returns:
true if this file is a symbolic link

getDate

public long getDate()
Implementation note: for symlinks, returns the date of the link's target.

Specified by:
getDate in class AbstractFile
Returns:
this file's last modified date, in milliseconds since the epoch (00:00:00 GMT, January 1, 1970)

canChangeDate

public boolean canChangeDate()
Description copied from class: AbstractFile
Returns true if this file's date can be changed using AbstractFile.changeDate(long). It's important to note that a true return value doesn't mean that a call to AbstractFile.changeDate(long) will necessarily succeed ; it could fail because of unsufficient permissions or simply because of a low-level I/O ; but it should at least ensure that AbstractFile.changeDate(long) is implemented and has a chance of succeeding.

Specified by:
canChangeDate in class AbstractFile
Returns:
true if this file's date can be changed using AbstractFile.changeDate(long)

changeDate

public boolean changeDate(long lastModified)
Description copied from class: AbstractFile
Changes last modified date and returns true if date was changed successfully, false if the operation could not be completed, either because this method is not implemented for this file type, or because of insufficient permissions or a low-level I/O error.

Specified by:
changeDate in class AbstractFile
Parameters:
lastModified - last modified date, in milliseconds since the epoch (00:00:00 GMT, January 1, 1970)
Returns:
true if date was changed successfully.

getSize

public long getSize()
Implementation note: for symlinks, returns the size of the link's target.

Specified by:
getSize in class AbstractFile
Returns:
this file's size in bytes, 0 if this file doesn't exist, -1 if the size is undetermined

getParent

public AbstractFile getParent()
                       throws java.io.IOException
Description copied from class: AbstractFile
Returns this file's parent, null if it doesn't have one.

Specified by:
getParent in class AbstractFile
Returns:
this file's parent, null if it doesn't have one
Throws:
java.io.IOException - if the parent file could not be instanciated

setParent

public void setParent(AbstractFile parent)
Description copied from class: AbstractFile
Sets this file's parent. null can be specified if this file doesn't have a parent.

Specified by:
setParent in class AbstractFile
Parameters:
parent - the new parent of this file

exists

public boolean exists()
Implementation note: for symlinks, returns the value of the link's target.

Specified by:
exists in class AbstractFile
Returns:
true if this file exists

getPermissions

public FilePermissions getPermissions()
Implementation note: for symlinks, returns the permissions of the link's target.

Specified by:
getPermissions in class AbstractFile
Returns:
this file's permissions, as a FilePermissions object

getChangeablePermissions

public PermissionBits getChangeablePermissions()
Description copied from class: AbstractFile
Returns a bit mask describing the permission bits that can be changed on this file when calling AbstractFile.changePermission(int, int, boolean) and AbstractFile.changePermissions(int).

Specified by:
getChangeablePermissions in class AbstractFile
Returns:
a bit mask describing the permission bits that can be changed on this file

changePermission

public boolean changePermission(int access,
                                int permission,
                                boolean enabled)
Description copied from class: AbstractFile
Changes the specified permission bit. If the specified permission bit can't be changed (see AbstractFile.getChangeablePermissions()), this method has no effect and false is returned.

Specified by:
changePermission in class AbstractFile
Parameters:
access - see PermissionTypes for allowed values
permission - see PermissionAccesses for allowed values
enabled - true to enable the flag, false to disable it
Returns:
true if the permission flag was successfully set for the access type
See Also:
AbstractFile.getChangeablePermissions()

getOwner

public java.lang.String getOwner()
Description copied from class: AbstractFile
Returns information about the owner of this file. The kind of information that is returned is implementation-dependant. It may typically be a username (e.g. 'bob') or a user ID (e.g. '501'). If the owner information is not available to the AbstractFile implementation (cannot be retrieved or the filesystem doesn't have any notion of owner) or not available for this particular file, null will be returned.

Specified by:
getOwner in class AbstractFile
Returns:
information about the owner of this file

canGetOwner

public boolean canGetOwner()
Description copied from class: AbstractFile
Returns true if this file implementation is able to return some information about file owners, not necessarily for all files or this file in particular but at least for some of them. In other words, a true return value doesn't mean that AbstractFile.getOwner() will necessarily return a non-null value, but rather that there is a chance that it does.

Specified by:
canGetOwner in class AbstractFile
Returns:
true if this file implementation is able to return information about file owners

getGroup

public java.lang.String getGroup()
Description copied from class: AbstractFile
Returns information about the group this file belongs to. The kind of information that is returned is implementation-dependant. It may typically be a group name (e.g. 'www-data') or a group ID (e.g. '501'). If the group information is not available to the AbstractFile implementation (cannot be retrieved or the filesystem doesn't have any notion of owner) or not available for this particular file, null will be returned.

Specified by:
getGroup in class AbstractFile
Returns:
information about the owner of this file

canGetGroup

public boolean canGetGroup()
Description copied from class: AbstractFile
Returns true if this file implementation is able to return some information about file groups, not necessarily for all files or this file in particular but at least for some of them. In other words, a true return value doesn't mean that AbstractFile.getGroup() will necessarily return a non-null value, but rather that there is a chance that it does.

Specified by:
canGetGroup in class AbstractFile
Returns:
true if this file implementation is able to return information about file groups

isDirectory

public boolean isDirectory()
Implementation note: for symlinks, returns the value of the link's target.

Specified by:
isDirectory in class AbstractFile
Returns:
true if this file is a directory, false in any of the cases listed above

getInputStream

public java.io.InputStream getInputStream()
                                   throws java.io.IOException
Description copied from class: AbstractFile
Returns an InputStream to read the contents of this file. Throws an IOException in any of the following cases: This method may never return null.

Specified by:
getInputStream in class AbstractFile
Returns:
an InputStream to read the contents of this file
Throws:
java.io.IOException - in any of the cases listed above

getOutputStream

public java.io.OutputStream getOutputStream(boolean append)
                                     throws java.io.IOException
Description copied from class: AbstractFile
Returns an OuputStream to write the contents of this file, appending or overwriting the existing contents. This file will be created as a zero-byte file if it does not yet exist. Throws an IOException in any of the following cases: This method may never return null.

Specified by:
getOutputStream in class AbstractFile
Parameters:
append - if true, data written to the OutputStream will be appended to the end of this file. If false, any existing data this file contains will be discarded and overwritten.
Returns:
an OuputStream to write the contents of this file
Throws:
java.io.IOException - in any of the cases listed above

hasRandomAccessInputStream

public boolean hasRandomAccessInputStream()
Returns true: getRandomAccessInputStream() is implemented.

Specified by:
hasRandomAccessInputStream in class AbstractFile
Returns:
true

getRandomAccessInputStream

public RandomAccessInputStream getRandomAccessInputStream()
                                                   throws java.io.IOException
Description copied from class: AbstractFile
Returns a RandomAccessInputStream to read the contents of this file with random access. Throws an IOException in any of the following cases: This method may never return null.

Specified by:
getRandomAccessInputStream in class AbstractFile
Returns:
a RandomAccessInputStream to read the contents of this file with random access
Throws:
java.io.IOException - in any of the cases listed above

hasRandomAccessOutputStream

public boolean hasRandomAccessOutputStream()
Returns false: getRandomAccessOutputStream() is not implemented and throws an IOException.

Specified by:
hasRandomAccessOutputStream in class AbstractFile
Returns:
false

getRandomAccessOutputStream

public RandomAccessOutputStream getRandomAccessOutputStream()
                                                     throws java.io.IOException
Description copied from class: AbstractFile
Returns a RandomAccessOutputStream to write the contents of this file with random access. This file will be created as a zero-byte file if it does not yet exist. Throws an IOException in any of the following cases: This method may never return null.

Specified by:
getRandomAccessOutputStream in class AbstractFile
Returns:
a RandomAccessOutputStream to write the contents of this file with random access
Throws:
java.io.IOException - in any of the cases listed above

delete

public void delete()
            throws java.io.IOException
Description copied from class: AbstractFile
Deletes this file and this file only (does not recurse on folders). Throws an IOException in any of the following cases:

Specified by:
delete in class AbstractFile
Throws:
java.io.IOException - if this file does not exist or could not be deleted

ls

public AbstractFile[] ls()
                  throws java.io.IOException
Description copied from class: AbstractFile
Returns the children files that this file contains. For this operation to be successful, this file must be 'browsable', i.e. AbstractFile.isBrowsable() must return true. This method may return a zero-length array if it has no children but may never return null.

Specified by:
ls in class AbstractFile
Returns:
the children files that this file contains
Throws:
java.io.IOException - if this operation is not possible (file is not browsable) or if an error occurred.

mkdir

public void mkdir()
           throws java.io.IOException
Description copied from class: AbstractFile
Creates this file as a directory. This method will fail (throw an IOException) if this file already exists.

Specified by:
mkdir in class AbstractFile
Throws:
java.io.IOException - if the directory could not be created, either because this file already exists or for any other reason.

getFreeSpace

public long getFreeSpace()
Description copied from class: AbstractFile
Returns the free space (in bytes) on the disk/volume where this file is, -1 if this information is not available.

Specified by:
getFreeSpace in class AbstractFile
Returns:
the free space (in bytes) on the disk/volume where this file is, -1 if this information is not available.

getTotalSpace

public long getTotalSpace()
Description copied from class: AbstractFile
Returns the total space (in bytes) of the disk/volume where this file is, -1 if this information is not available.

Specified by:
getTotalSpace in class AbstractFile
Returns:
the total space (in bytes) of the disk/volume where this file is, -1 if this information is not available

getUnderlyingFileObject

public java.lang.Object getUnderlyingFileObject()
Returns a SFTPFile.SFTPFileAttributes instance corresponding to this file.

Specified by:
getUnderlyingFileObject in class AbstractFile
Returns:
the file Object of the underlying API providing access to the filesystem, null if there is none

canRunProcess

public boolean canRunProcess()
Description copied from class: AbstractFile
Returns true if it's possible to run processes on the underlying file system.

Specified by:
canRunProcess in class AbstractFile
Returns:
true if it's possible to run processes on the underlying file system, false otherwise.

runProcess

public AbstractProcess runProcess(java.lang.String[] tokens)
                           throws java.io.IOException
Description copied from class: AbstractFile
Creates a process executing the specified command tokens using this file as a working directory.

Specified by:
runProcess in class AbstractFile
Parameters:
tokens - command and its arguments for the process to create.
Returns:
a process executing the specified command tokens using this file as a working directory.
Throws:
java.io.IOException - thrown if an error occured while creating the process, if the current file is not a directory or if the operation is not supported.

changePermissions

public boolean changePermissions(int permissions)
Description copied from class: AbstractFile
Changes this file's permissions to the specified permissions int and returns true if the operation was successful, false if at least one of the file permissions could not be changed. The permissions int should be constructed using the permission types and accesses defined in PermissionTypes and PermissionAccesses.

Implementation note: the default implementation of this method calls sequentially AbstractFile.changePermission(int, int, boolean), for each permission and access (that's a total 9 calls). This may affect performance on filesystems which need to perform an I/O request to change each permission individually. In that case, and if the fileystem allows to change all permissions at once, this method should be overridden.

Overrides:
changePermissions in class AbstractFile
Parameters:
permissions - new permissions for this file
Returns:
true if the operation was successful, false if at least one of the file permissions could not be changed

moveTo

public boolean moveTo(AbstractFile destFile)
               throws FileTransferException
Overrides AbstractFile.moveTo(AbstractFile) to support server-to-server move if the destination file uses SFTP and is located on the same host.

Overrides:
moveTo in class AbstractFile
Parameters:
destFile - the destination file to move this file to
Returns:
true if the operation could be successfully be completed, false if the operation could not be performed because of unsatisfied conditions (not an error)
Throws:
FileTransferException - in any of the cases listed above, use FileTransferException.getReason() to know the reason.

getInputStream

public java.io.InputStream getInputStream(long offset)
                                   throws java.io.IOException
Description copied from class: AbstractFile
Returns an InputStream to read this file's contents, starting at the specified offset (in bytes). A java.io.IOException is thrown if the file doesn't exist.

This method should be overridden whenever possible to provide a more efficient implementation as this default implementation uses InputStream.skip(long) which, depending on the particular InputStream implementation may just read bytes and discards them, which is very slow.

Overrides:
getInputStream in class AbstractFile
Parameters:
offset - the offset in bytes from the beginning of the file, must be >0
Returns:
an InputStream to read this file's contents, skipping the specified number of bytes
Throws:
java.io.IOException - if this file cannot be read or is a folder.

getCanonicalPath

public java.lang.String getCanonicalPath()
Description copied from class: AbstractFile
Returns the canonical path to this file, resolving any symbolic links or '..' and '.' occurrences.

This implementation simply returns the value of AbstractFile.getAbsolutePath(), and thus should be overridden if canonical path resolution is available.

Overrides:
getCanonicalPath in class AbstractFile
Returns:
the canonical path to this file


This file is part of muCommander - Copyright (C) 2002-2008 Maxence Bernard