/** * Copyright 2003-2016 SSHTOOLS Limited. All Rights Reserved. * * For product documentation visit https://www.sshtools.com/ * * This file is part of J2SSH Maverick. * * J2SSH Maverick is free software: you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * J2SSH Maverick 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 J2SSH Maverick. If not, see <http://www.gnu.org/licenses/>. */ package com.sshtools.sftp; import com.sshtools.ssh.SshException; /** * Represents an SFTP file object. * * @author Lee David Painter */ public class SftpFile { String filename; byte[] handle; SftpFileAttributes attrs; SftpSubsystemChannel sftp; String absolutePath; String longname; /** * Creates a new SftpFile object. * * @param path * @param attrs */ public SftpFile(String path, SftpFileAttributes attrs) { absolutePath = path; this.attrs = attrs; // set filename if (absolutePath.equals("/")) { this.filename = "/"; } else { absolutePath = absolutePath.trim(); // Remove trailing forward slash if (absolutePath.endsWith("/")) { absolutePath = absolutePath.substring(0, absolutePath.length() - 1); } int i = absolutePath.lastIndexOf('/'); // if absolutePath contains / then filename= name following last /, // else filename=absolutePath if (i > -1) { this.filename = absolutePath.substring(i + 1); } else { this.filename = absolutePath; } } } /** * Get the parent of the current file. This method determines the correct * path of the parent file; if no parent exists (i.e. the current file is * the root of the filesystem) then this method returns a null value. * * @return SftpFile * @throws SshException * @throws SftpStatusException */ public SftpFile getParent() throws SshException, SftpStatusException { if (absolutePath.lastIndexOf('/') == -1) { // This is simply a filename so the parent is the users default // directory String dir = sftp.getDefaultDirectory(); return sftp.getFile(dir); } // Extract the filename from the absolute path and return the parent String path = sftp.getAbsolutePath(absolutePath); if (path.equals("/")) return null; // If we have . or .. then strip the path and let getParent start over // again with the correct canonical path if (filename.equals(".") || filename.equals("..")) { return sftp.getFile(path).getParent(); } int idx = path.lastIndexOf('/'); String parent = path.substring(0, idx); // Check if we at the root if so we will have to add / if (parent.equals("")) parent = "/"; return sftp.getFile(parent); } public String toString() { return absolutePath; } public int hashCode() { return absolutePath.hashCode(); } public String getLongname() { return longname; } /** * Compares the Object to this instance and returns true if they point to * the same file. If they point to the same file but have open file handles, * the handles are also used to determine the equality. Therefore two * separate instances both pointing to the same file will return true, * unless one or both have an open file handle in which case it will only * return true if the file handles also match. * * @param obj * @return boolean */ public boolean equals(Object obj) { if (obj instanceof SftpFile) { boolean match = ((SftpFile) obj).getAbsolutePath().equals( absolutePath); if (handle == null && (((SftpFile) obj).handle == null)) { return match; } if (handle != null && ((SftpFile) obj).handle != null) { for (int i = 0; i < handle.length; i++) { if (((SftpFile) obj).handle[i] != handle[i]) return false; } } return match; } return false; } /** * Delete this file/directory from the remote server. * * @throws SshException * @throws SftpStatusException */ public void delete() throws SftpStatusException, SshException { if (sftp == null) { throw new SshException("Instance not connected to SFTP subsystem", SshException.BAD_API_USAGE); } if (isDirectory()) { sftp.removeDirectory(getAbsolutePath()); } else { sftp.removeFile(getAbsolutePath()); } } /** * Determine whether the user has write access to the file. This checks the * S_IWUSR flag is set in permissions. * * @return boolean * @throws SftpStatusException * @throws SshException */ public boolean canWrite() throws SftpStatusException, SshException { // This is long hand because gcj chokes when it is not? Investigate why if ((getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IWUSR) == SftpFileAttributes.S_IWUSR || (getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IWGRP) == SftpFileAttributes.S_IWGRP || (getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IWOTH) == SftpFileAttributes.S_IWOTH) { return true; } return false; } /** * Determine whether the user has read access to the file. This checks the * S_IRUSR flag is set in permissions. * * @return boolean * @throws SftpStatusException * @throws SshException */ public boolean canRead() throws SftpStatusException, SshException { // This is long hand because gcj chokes when it is not? Investigate why if ((getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IRUSR) == SftpFileAttributes.S_IRUSR || (getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IRGRP) == SftpFileAttributes.S_IRGRP || (getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IROTH) == SftpFileAttributes.S_IROTH) { return true; } return false; } /** * Determine whether the file is open. * * @return boolean */ public boolean isOpen() { if (sftp == null) { return false; } return handle != null; } /** * Set the open file handle * * @param handle */ void setHandle(byte[] handle) { this.handle = handle; } /** * Get the open file handle * * @return byte[] */ public byte[] getHandle() { return handle; } /** * Sets the SFTP subsystem * * @param sftp */ void setSFTPSubsystem(SftpSubsystemChannel sftp) { this.sftp = sftp; } /** * Get the SFTP subsystem channel that created this file object. * * @return SftpSubsystemChannel */ public SftpSubsystemChannel getSFTPChannel() { return sftp; } /** * Get the filename. * * @return String */ public String getFilename() { return filename; } /** * Get the files attributes. * * @return SftpFileAttributes * @throws SshException * @throws SftpStatusException */ public SftpFileAttributes getAttributes() throws SftpStatusException, SshException { if (attrs == null) { attrs = sftp.getAttributes(getAbsolutePath()); } return attrs; } /** * Get the absolute path * * @return String */ public String getAbsolutePath() { return absolutePath; } /** * Close the file. * * @throws SshException * @throws SftpStatusException */ public void close() throws SftpStatusException, SshException { sftp.closeFile(this); } /** * Determine whether the file object is pointing to a directory. Note, if * the file is a symbolic link pointing to a directory then * <code>false</code> will be returned. Use * {@link com.sshtools.sftp.SftpClient#isDirectoryOrLinkedDirectory(SftpFile)} * instead if you wish to follow links. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isDirectory() throws SftpStatusException, SshException { return getAttributes().isDirectory(); } /** * Determine whether the file object is pointing to a file. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isFile() throws SftpStatusException, SshException { return getAttributes().isFile(); } /** * Determine whether the file object is a symbolic link. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isLink() throws SftpStatusException, SshException { return getAttributes().isLink(); } /** * Determine whether the file is pointing to a pipe. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isFifo() throws SftpStatusException, SshException { // This is long hand because gcj chokes when it is not? Investigate why if ((getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IFIFO) == SftpFileAttributes.S_IFIFO) return true; return false; } /** * Determine whether the file is pointing to a block special file. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isBlock() throws SftpStatusException, SshException { // This is long hand because gcj chokes when it is not? Investigate why if ((getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IFBLK) == SftpFileAttributes.S_IFBLK) { return true; } return false; } /** * Determine whether the file is pointing to a character mode device. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isCharacter() throws SftpStatusException, SshException { // This is long hand because gcj chokes when it is not? Investigate why if ((getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IFCHR) == SftpFileAttributes.S_IFCHR) { return true; } return false; } /** * Determine whether the file is pointing to a socket. * * @return boolean * @throws SshException * @throws SftpStatusException */ public boolean isSocket() throws SftpStatusException, SshException { // This is long hand because gcj chokes when it is not? Investigate why if ((getAttributes().getPermissions().longValue() & SftpFileAttributes.S_IFSOCK) == SftpFileAttributes.S_IFSOCK) { return true; } return false; } }