Save This Page
Home » j2ssh-0.2.9-src » com.sshtools.j2ssh » [javadoc | source]
    1   /*
    2    *  SSHTools - Java SSH2 API
    3    *
    4    *  Copyright (C) 2002-2003 Lee David Painter and Contributors.
    5    *
    6    *  Contributions made by:
    7    *
    8    *  Brett Smith
    9    *  Richard Pernavas
   10    *  Erwin Bolwidt
   11    *
   12    *  This program is free software; you can redistribute it and/or
   13    *  modify it under the terms of the GNU General Public License
   14    *  as published by the Free Software Foundation; either version 2
   15    *  of the License, or (at your option) any later version.
   16    *
   17    *  This program is distributed in the hope that it will be useful,
   18    *  but WITHOUT ANY WARRANTY; without even the implied warranty of
   19    *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   20    *  GNU General Public License for more details.
   21    *
   22    *  You should have received a copy of the GNU General Public License
   23    *  along with this program; if not, write to the Free Software
   24    *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
   25    */
   26   package com.sshtools.j2ssh;
   27   
   28   import com.sshtools.j2ssh.connection;
   29   import com.sshtools.j2ssh.io;
   30   import com.sshtools.j2ssh.sftp;
   31   
   32   import java.io.File;
   33   import java.io.FileInputStream;
   34   import java.io.FileNotFoundException;
   35   import java.io.FileOutputStream;
   36   import java.io.IOException;
   37   import java.io.InputStream;
   38   import java.io.OutputStream;
   39   
   40   import java.util.Iterator;
   41   import java.util.List;
   42   import java.util.StringTokenizer;
   43   import java.util.Vector;
   44   
   45   
   46   /**
   47    * <p>
   48    * Implements a Secure File Transfer (SFTP) client.
   49    * </p>
   50    *
   51    * @author Lee David Painter
   52    * @version $Revision: 1.44 $
   53    *
   54    * @since 0.2.0
   55    */
   56   public class SftpClient {
   57       SftpSubsystemClient sftp;
   58       String cwd;
   59       String lcwd;
   60       private int BLOCKSIZE = 65535;
   61   
   62       // Default permissions is determined by default_permissions ^ umask
   63       int umask = 0022;
   64       int default_permissions = 0777;
   65   
   66       /**
   67        * <p>
   68        * Constructs the SFTP client.
   69        * </p>
   70        *
   71        * @param ssh the <code>SshClient</code> instance
   72        *
   73        * @throws IOException if an IO error occurs
   74        */
   75       SftpClient(SshClient ssh) throws IOException {
   76           this(ssh, null);
   77       }
   78   
   79       /**
   80        * <p>
   81        * Constructs the SFTP client with a given channel event listener.
   82        * </p>
   83        *
   84        * @param ssh the <code>SshClient</code> instance
   85        * @param eventListener an event listener implementation
   86        *
   87        * @throws IOException if an IO error occurs
   88        */
   89       SftpClient(SshClient ssh, ChannelEventListener eventListener)
   90           throws IOException {
   91           if (!ssh.isConnected()) {
   92               throw new IOException("SshClient is not connected");
   93           }
   94   
   95           this.sftp = ssh.openSftpChannel(eventListener);
   96   
   97           // Get the users default directory
   98           cwd = sftp.getDefaultDirectory();
   99           lcwd = System.getProperty("user.home");
  100       }
  101   
  102       /**
  103        * Sets the umask used by this client.
  104        * @param umask
  105        * @return the previous umask value
  106        */
  107       public int umask(int umask) {
  108           int old = umask;
  109           this.umask = umask;
  110   
  111           return old;
  112       }
  113   
  114       /**
  115        * <p>
  116        * Changes the working directory on the remote server.
  117        * </p>
  118        *
  119        * @param dir the new working directory
  120        *
  121        * @throws IOException if an IO error occurs or the file does not exist
  122        * @throws FileNotFoundException
  123        *
  124        * @since 0.2.0
  125        */
  126       public void cd(String dir) throws IOException {
  127           try {
  128               String actual;
  129   
  130               if (dir.equals("")) {
  131                   actual = sftp.getDefaultDirectory();
  132               } else {
  133                   actual = resolveRemotePath(dir);
  134                   actual = sftp.getAbsolutePath(actual);
  135               }
  136   
  137               FileAttributes attr = sftp.getAttributes(actual);
  138   
  139               if (!attr.isDirectory()) {
  140                   throw new IOException(dir + " is not a directory");
  141               }
  142   
  143               cwd = actual;
  144           } catch (IOException ex) {
  145               throw new FileNotFoundException(dir + " could not be found");
  146           }
  147       }
  148   
  149       private File resolveLocalPath(String path) throws IOException {
  150           File f = new File(path);
  151   
  152           if (!f.isAbsolute()) {
  153               f = new File(lcwd, path);
  154           }
  155   
  156           return f;
  157       }
  158   
  159       private String resolveRemotePath(String path) throws IOException {
  160           verifyConnection();
  161   
  162           String actual;
  163   
  164           if (!path.startsWith("/")) {
  165               actual = cwd + (cwd.endsWith("/") ? "" : "/") + path;
  166           } else {
  167               actual = path;
  168           }
  169   
  170           return actual;
  171       }
  172   
  173       private void verifyConnection() throws SshException {
  174           if (sftp.isClosed()) {
  175               throw new SshException("The SFTP connection has been closed");
  176           }
  177       }
  178   
  179       /**
  180        * <p>
  181        * Creates a new directory on the remote server. This method will throw an
  182        * exception if the directory already exists. To create directories and
  183        * disregard any errors use the <code>mkdirs</code> method.
  184        * </p>
  185        *
  186        * @param dir the name of the new directory
  187        *
  188        * @throws IOException if an IO error occurs or if the directory already
  189        *         exists
  190        *
  191        * @since 0.2.0
  192        */
  193       public void mkdir(String dir) throws IOException {
  194           String actual = resolveRemotePath(dir);
  195   
  196           try {
  197               FileAttributes attrs = stat(actual);
  198   
  199               if (!attrs.isDirectory()) {
  200                   throw new IOException("File already exists named " + dir);
  201               }
  202           } catch (IOException ex) {
  203               sftp.makeDirectory(actual);
  204               chmod(default_permissions ^ umask, actual);
  205           }
  206       }
  207   
  208       /**
  209        * <p>
  210        * Create a directory or set of directories. This method will not fail even
  211        * if the directories exist. It is advisable to test whether the directory
  212        * exists before attempting an operation by using the <code>stat</code>
  213        * method to return the directories attributes.
  214        * </p>
  215        *
  216        * @param dir the path of directories to create.
  217        */
  218       public void mkdirs(String dir) {
  219           StringTokenizer tokens = new StringTokenizer(dir, "/");
  220           String path = dir.startsWith("/") ? "/" : "";
  221   
  222           while (tokens.hasMoreElements()) {
  223               path += (String) tokens.nextElement();
  224   
  225               try {
  226                   stat(path);
  227               } catch (IOException ex) {
  228                   try {
  229                       mkdir(path);
  230                   } catch (IOException ex2) {
  231                   }
  232               }
  233   
  234               path += "/";
  235           }
  236       }
  237   
  238       /**
  239        * <p>
  240        * Returns the absolute path name of the current remote working directory.
  241        * </p>
  242        *
  243        * @return the absolute path of the remote working directory.
  244        *
  245        * @since 0.2.0
  246        */
  247       public String pwd() {
  248           return cwd;
  249       }
  250   
  251       /**
  252        * <p>
  253        * List the contents of the current remote working directory.
  254        * </p>
  255        *
  256        * <p>
  257        * Returns a list of <code>SftpFile</code> instances for the current
  258        * working directory.
  259        * </p>
  260        *
  261        * @return a list of SftpFile for the current working directory
  262        *
  263        * @throws IOException if an IO error occurs
  264        *
  265        * @see com.sshtools.j2ssh.sftp.SftpFile
  266        * @since 0.2.0
  267        */
  268       public List ls() throws IOException {
  269           return ls(cwd);
  270       }
  271   
  272       /**
  273        * <p>
  274        * List the contents remote directory.
  275        * </p>
  276        *
  277        * <p>
  278        * Returns a list of <code>SftpFile</code> instances for the remote
  279        * directory.
  280        * </p>
  281        *
  282        * @param path the path on the remote server to list
  283        *
  284        * @return a list of SftpFile for the remote directory
  285        *
  286        * @throws IOException if an IO error occurs
  287        *
  288        * @see com.sshtools.j2ssh.sftp.SftpFile
  289        * @since 0.2.0
  290        */
  291       public List ls(String path) throws IOException {
  292           String actual = resolveRemotePath(path);
  293           FileAttributes attrs = sftp.getAttributes(actual);
  294   
  295           if (!attrs.isDirectory()) {
  296               throw new IOException(path + " is not a directory");
  297           }
  298   
  299           SftpFile file = sftp.openDirectory(actual);
  300           Vector children = new Vector();
  301   
  302           while (sftp.listChildren(file, children) > -1) {
  303               ;
  304           }
  305   
  306           file.close();
  307   
  308           return children;
  309       }
  310   
  311       /**
  312        * <p>
  313        * Changes the local working directory.
  314        * </p>
  315        *
  316        * @param path the path to the new working directory
  317        *
  318        * @throws IOException if an IO error occurs
  319        *
  320        * @since 0.2.0
  321        */
  322       public void lcd(String path) throws IOException {
  323           File actual;
  324   
  325           if (!isLocalAbsolutePath(path)) {
  326               actual = new File(lcwd, path);
  327           } else {
  328               actual = new File(path);
  329           }
  330   
  331           if (!actual.isDirectory()) {
  332               throw new IOException(path + " is not a directory");
  333           }
  334   
  335           lcwd = actual.getCanonicalPath();
  336       }
  337   
  338       private static boolean isLocalAbsolutePath(String path) {
  339           return (new File(path)).isAbsolute();
  340       }
  341   
  342       /**
  343        * <p>
  344        * Returns the absolute path to the local working directory.
  345        * </p>
  346        *
  347        * @return the absolute path of the local working directory.
  348        *
  349        * @since 0.2.0
  350        */
  351       public String lpwd() {
  352           return lcwd;
  353       }
  354   
  355       /**
  356        * <p>
  357        * Download the remote file to the local computer.
  358        * </p>
  359        *
  360        * @param path the path to the remote file
  361        * @param progress
  362        *
  363        * @return
  364        *
  365        * @throws IOException if an IO error occurs of the file does not exist
  366        * @throws TransferCancelledException
  367        *
  368        * @since 0.2.0
  369        */
  370       public FileAttributes get(String path, FileTransferProgress progress)
  371           throws IOException, TransferCancelledException {
  372           String localfile;
  373   
  374           if (path.lastIndexOf("/") > -1) {
  375               localfile = path.substring(path.lastIndexOf("/") + 1);
  376           } else {
  377               localfile = path;
  378           }
  379   
  380           return get(path, localfile, progress);
  381       }
  382   
  383       /**
  384        *
  385        *
  386        * @param path
  387        *
  388        * @return
  389        *
  390        * @throws IOException
  391        */
  392       public FileAttributes get(String path) throws IOException {
  393           return get(path, (FileTransferProgress) null);
  394       }
  395   
  396       private void transferFile(InputStream in, OutputStream out)
  397           throws IOException, TransferCancelledException {
  398           transferFile(in, out, null);
  399       }
  400   
  401       private void transferFile(
  402           InputStream in, 
  403           OutputStream out,
  404           FileTransferProgress progress)
  405         throws IOException, TransferCancelledException 
  406       {
  407         try {
  408           long bytesSoFar = 0;
  409           byte[] buffer = new byte[BLOCKSIZE];
  410           int read;
  411           
  412           while ((read = in.read(buffer)) > -1) {
  413             if ((progress != null) && progress.isCancelled()) {
  414               throw new TransferCancelledException();
  415             }
  416             
  417             if (read > 0) {
  418               out.write(buffer, 0, read);
  419               
  420               //out.flush();
  421               bytesSoFar += read;
  422               
  423               if (progress != null) {
  424                 progress.progressed(bytesSoFar);
  425               }
  426             }
  427           }
  428         } 
  429         finally {
  430           try {
  431             in.close();
  432             out.close();
  433           } 
  434           catch (IOException ex) {
  435           }
  436         }
  437       }
  438   
  439       /**
  440        * <p>
  441        * Download the remote file to the local computer. If the paths provided
  442        * are not absolute the current working directory is used.
  443        * </p>
  444        *
  445        * @param remote the path/name of the remote file
  446        * @param local the path/name to place the file on the local computer
  447        * @param progress
  448        *
  449        * @return
  450        *
  451        * @throws IOException if an IO error occurs or the file does not exist
  452        * @throws TransferCancelledException
  453        *
  454        * @since 0.2.0
  455        */
  456       public FileAttributes get(String remote, String local,
  457           FileTransferProgress progress)
  458           throws IOException, TransferCancelledException {
  459           File localPath = resolveLocalPath(local);
  460   
  461           if (!localPath.exists()) {
  462               localPath.getParentFile().mkdirs();
  463               localPath.createNewFile();
  464           }
  465   
  466           FileOutputStream out = new FileOutputStream(localPath);
  467   
  468           return get(remote, out, progress);
  469       }
  470   
  471       /**
  472        *
  473        *
  474        * @param remote
  475        * @param local
  476        *
  477        * @return
  478        *
  479        * @throws IOException
  480        */
  481       public FileAttributes get(String remote, String local)
  482           throws IOException {
  483           return get(remote, local, null);
  484       }
  485   
  486       /**
  487        * <p>
  488        * Download the remote file writing it to the specified
  489        * <code>OutputStream</code>. The OutputStream is closed by this mehtod
  490        * even if the operation fails.
  491        * </p>
  492        *
  493        * @param remote the path/name of the remote file
  494        * @param local the OutputStream to write
  495        * @param progress
  496        *
  497        * @return
  498        *
  499        * @throws IOException if an IO error occurs or the file does not exist
  500        * @throws TransferCancelledException
  501        *
  502        * @since 0.2.0
  503        */
  504       public FileAttributes get(String remote, OutputStream local,
  505           FileTransferProgress progress)
  506           throws IOException, TransferCancelledException {
  507           String remotePath = resolveRemotePath(remote);
  508           FileAttributes attrs = stat(remotePath);
  509   
  510           if (progress != null) {
  511               progress.started(attrs.getSize().longValue(), remotePath);
  512           }
  513   
  514           SftpFileInputStream in = new SftpFileInputStream(sftp.openFile(
  515                       remotePath, SftpSubsystemClient.OPEN_READ));
  516           transferFile(in, local, progress);
  517   
  518           if (progress != null) {
  519               progress.completed();
  520           }
  521   
  522           return attrs;
  523       }
  524   
  525       /**
  526        *
  527        *
  528        * @param remote
  529        * @param local
  530        *
  531        * @return
  532        *
  533        * @throws IOException
  534        */
  535       public FileAttributes get(String remote, OutputStream local)
  536           throws IOException {
  537           return get(remote, local, null);
  538       }
  539   
  540       /**
  541        * <p>
  542        * Returns the state of the SFTP client. The client is closed if the
  543        * underlying session channel is closed. Invoking the <code>quit</code>
  544        * method of this object will close the underlying session channel.
  545        * </p>
  546        *
  547        * @return true if the client is still connected, otherwise false
  548        *
  549        * @since 0.2.0
  550        */
  551       public boolean isClosed() {
  552           return sftp.isClosed();
  553       }
  554   
  555       /**
  556        * <p>
  557        * Upload a file to the remote computer.
  558        * </p>
  559        *
  560        * @param local the path/name of the local file
  561        * @param progress
  562        *
  563        * @return
  564        *
  565        * @throws IOException if an IO error occurs or the file does not exist
  566        * @throws TransferCancelledException
  567        *
  568        * @since 0.2.0
  569        */
  570       public void put(String local, FileTransferProgress progress)
  571           throws IOException, TransferCancelledException {
  572           File f = new File(local);
  573           put(local, f.getName(), progress);
  574       }
  575   
  576       /**
  577        *
  578        *
  579        * @param local
  580        *
  581        * @return
  582        *
  583        * @throws IOException
  584        */
  585       public void put(String local) throws IOException {
  586           put(local, (FileTransferProgress) null);
  587       }
  588   
  589       /**
  590        * <p>
  591        * Upload a file to the remote computer. If the paths provided are not
  592        * absolute the current working directory is used.
  593        * </p>
  594        *
  595        * @param local the path/name of the local file
  596        * @param remote the path/name of the destination file
  597        * @param progress
  598        *
  599        * @return
  600        *
  601        * @throws IOException if an IO error occurs or the file does not exist
  602        * @throws TransferCancelledException
  603        *
  604        * @since 0.2.0
  605        */
  606       public void put(String local, String remote, FileTransferProgress progress)
  607           throws IOException, TransferCancelledException {
  608           File localPath = resolveLocalPath(local);
  609           FileInputStream in = new FileInputStream(localPath);
  610   
  611           try {
  612               FileAttributes attrs = stat(remote);
  613   
  614               if (attrs.isDirectory()) {
  615                   File f = new File(local);
  616                   remote += ((remote.endsWith("/") ? "" : "/") + f.getName());
  617               }
  618           } catch (IOException ex) {
  619           }
  620   
  621           put(in, remote, progress);
  622       }
  623   
  624       /**
  625        *
  626        *
  627        * @param local
  628        * @param remote
  629        *
  630        * @return
  631        *
  632        * @throws IOException
  633        */
  634       public void put(String local, String remote) throws IOException {
  635           put(local, remote, null);
  636       }
  637   
  638       /**
  639        * <p>
  640        * Upload a file to the remote computer reading from the specified <code>
  641        * InputStream</code>. The InputStream is closed, even if the operation
  642        * fails.
  643        * </p>
  644        *
  645        * @param in the InputStream being read
  646        * @param remote the path/name of the destination file
  647        * @param progress
  648        *
  649        * @return
  650        *
  651        * @throws IOException if an IO error occurs
  652        * @throws TransferCancelledException
  653        *
  654        * @since 0.2.0
  655        */
  656       public void put(InputStream in, String remote, FileTransferProgress progress)
  657           throws IOException, TransferCancelledException {
  658           String remotePath = resolveRemotePath(remote);
  659           SftpFileOutputStream out;
  660           FileAttributes attrs;
  661           boolean newfile = false;
  662   
  663           try {
  664               attrs = stat(remotePath);
  665               out = new SftpFileOutputStream(sftp.openFile(remotePath,
  666                           SftpSubsystemClient.OPEN_CREATE |
  667                           SftpSubsystemClient.OPEN_TRUNCATE |
  668                           SftpSubsystemClient.OPEN_WRITE));
  669           } catch (IOException ex) {
  670               attrs = new FileAttributes();
  671               newfile = true;
  672               attrs.setPermissions(new UnsignedInteger32(default_permissions ^
  673                       umask));
  674               out = new SftpFileOutputStream(sftp.openFile(remotePath,
  675                           SftpSubsystemClient.OPEN_CREATE |
  676                           SftpSubsystemClient.OPEN_WRITE, attrs));
  677           }
  678   
  679           if (progress != null) {
  680               progress.started(in.available(), remotePath);
  681           }
  682   
  683           transferFile(in, out, progress);
  684   
  685           if (progress != null) {
  686               progress.completed();
  687           }
  688   
  689           // Set the permissions here since at creation they dont always work
  690           if (newfile) {
  691               chmod(default_permissions ^ umask, remotePath);
  692           }
  693       }
  694   
  695       /**
  696        *
  697        *
  698        * @param in
  699        * @param remote
  700        *
  701        * @return
  702        *
  703        * @throws IOException
  704        */
  705       public void put(InputStream in, String remote) throws IOException {
  706           put(in, remote, null);
  707       }
  708   
  709       /**
  710        * <p>
  711        * Sets the user ID to owner for the file or directory.
  712        * </p>
  713        *
  714        * @param uid numeric user id of the new owner
  715        * @param path the path to the remote file/directory
  716        *
  717        * @throws IOException if an IO error occurs or the file does not exist
  718        *
  719        * @since 0.2.0
  720        */
  721       public void chown(int uid, String path) throws IOException {
  722           String actual = resolveRemotePath(path);
  723           FileAttributes attrs = sftp.getAttributes(actual);
  724           attrs.setUID(new UnsignedInteger32(uid));
  725           sftp.setAttributes(actual, attrs);
  726       }
  727   
  728       /**
  729        * <p>
  730        * Sets the group ID for the file or directory.
  731        * </p>
  732        *
  733        * @param gid the numeric group id for the new group
  734        * @param path the path to the remote file/directory
  735        *
  736        * @throws IOException if an IO error occurs or the file does not exist
  737        *
  738        * @since 0.2.0
  739        */
  740       public void chgrp(int gid, String path) throws IOException {
  741           String actual = resolveRemotePath(path);
  742           FileAttributes attrs = sftp.getAttributes(actual);
  743           attrs.setGID(new UnsignedInteger32(gid));
  744           sftp.setAttributes(actual, attrs);
  745       }
  746   
  747       /**
  748        * <p>
  749        * Changes the access permissions or modes of the specified file or
  750        * directory.
  751        * </p>
  752        *
  753        * <p>
  754        * Modes determine who can read, change or execute a file.
  755        * </p>
  756        * <blockquote><pre>Absolute modes are octal numbers specifying the complete list of
  757        * attributes for the files; you specify attributes by OR'ing together
  758        * these bits.
  759        *
  760        * 0400       Individual read
  761        * 0200       Individual write
  762        * 0100       Individual execute (or list directory)
  763        * 0040       Group read
  764        * 0020       Group write
  765        * 0010       Group execute
  766        * 0004       Other read
  767        * 0002       Other write
  768        * 0001       Other execute </pre></blockquote>
  769        *
  770        * @param permissions the absolute mode of the file/directory
  771        * @param path the path to the file/directory on the remote server
  772        *
  773        * @throws IOException if an IO error occurs or the file if not found
  774        *
  775        * @since 0.2.0
  776        */
  777       public void chmod(int permissions, String path) throws IOException {
  778           String actual = resolveRemotePath(path);
  779           sftp.changePermissions(actual, permissions);
  780       }
  781   
  782       public void umask(String umask) throws IOException {
  783           try {
  784               this.umask = Integer.parseInt(umask, 8);
  785           } catch (NumberFormatException ex) {
  786               throw new IOException(
  787                   "umask must be 4 digit octal number e.g. 0022");
  788           }
  789       }
  790   
  791       /**
  792        * <p>
  793        * Rename a file on the remote computer.
  794        * </p>
  795        *
  796        * @param oldpath the old path
  797        * @param newpath the new path
  798        *
  799        * @throws IOException if an IO error occurs
  800        *
  801        * @since 0.2.0
  802        */
  803       public void rename(String oldpath, String newpath)
  804           throws IOException {
  805           String from = resolveRemotePath(oldpath);
  806           String to = resolveRemotePath(newpath);
  807           sftp.renameFile(from, to);
  808       }
  809   
  810       /**
  811        * <p>
  812        * Remove a file or directory from the remote computer.
  813        * </p>
  814        *
  815        * @param path the path of the remote file/directory
  816        *
  817        * @throws IOException if an IO error occurs
  818        *
  819        * @since 0.2.0
  820        */
  821       public void rm(String path) throws IOException {
  822           String actual = resolveRemotePath(path);
  823           FileAttributes attrs = sftp.getAttributes(actual);
  824   
  825           if (attrs.isDirectory()) {
  826               sftp.removeDirectory(actual);
  827           } else {
  828               sftp.removeFile(actual);
  829           }
  830       }
  831   
  832       /**
  833        *
  834        *
  835        * @param path
  836        * @param force
  837        * @param recurse
  838        *
  839        * @throws IOException
  840        */
  841       public void rm(String path, boolean force, boolean recurse)
  842           throws IOException {
  843           String actual = resolveRemotePath(path);
  844           FileAttributes attrs = sftp.getAttributes(actual);
  845           SftpFile file;
  846   
  847           if (attrs.isDirectory()) {
  848               List list = ls(path);
  849   
  850               if (!force && (list.size() > 0)) {
  851                   throw new IOException(
  852                       "You cannot delete non-empty directory, use force=true to overide");
  853               } else {
  854                   for (Iterator it = list.iterator(); it.hasNext();) {
  855                       file = (SftpFile) it.next();
  856   
  857                       if (file.isDirectory() && !file.getFilename().equals(".") &&
  858                               !file.getFilename().equals("..")) {
  859                           if (recurse) {
  860                               rm(file.getAbsolutePath(), force, recurse);
  861                           } else {
  862                               throw new IOException(
  863                                   "Directory has contents, cannot delete without recurse=true");
  864                           }
  865                       } else if (file.isFile()) {
  866                           sftp.removeFile(file.getAbsolutePath());
  867                       }
  868                   }
  869               }
  870   
  871               sftp.removeDirectory(actual);
  872           } else {
  873               sftp.removeFile(actual);
  874           }
  875       }
  876   
  877       /**
  878        * <p>
  879        * Create a symbolic link on the remote computer.
  880        * </p>
  881        *
  882        * @param path the path to the existing file
  883        * @param link the new link
  884        *
  885        * @throws IOException if an IO error occurs or the operation is not
  886        *         supported on the remote platform
  887        *
  888        * @since 0.2.0
  889        */
  890       public void symlink(String path, String link) throws IOException {
  891           String actualPath = resolveRemotePath(path);
  892           String actualLink = resolveRemotePath(link);
  893           sftp.createSymbolicLink(actualPath, actualLink);
  894       }
  895   
  896       /**
  897        * <p>
  898        * Returns the attributes of the file from the remote computer.
  899        * </p>
  900        *
  901        * @param path the path of the file on the remote computer
  902        *
  903        * @return the attributes
  904        *
  905        * @throws IOException if an IO error occurs or the file does not exist
  906        *
  907        * @see com.sshtools.j2ssh.sftp.FileAttributes
  908        * @since 0.2.0
  909        */
  910       public FileAttributes stat(String path) throws IOException {
  911           String actual = resolveRemotePath(path);
  912   
  913           return sftp.getAttributes(actual);
  914       }
  915   
  916       /**
  917        *
  918        *
  919        * @param path
  920        *
  921        * @return
  922        *
  923        * @throws IOException
  924        */
  925       public String getAbsolutePath(String path) throws IOException {
  926           String actual = resolveRemotePath(path);
  927   
  928           return sftp.getAbsolutePath(path);
  929       }
  930   
  931       /**
  932        * <p>
  933        * Close the SFTP client.
  934        * </p>
  935        *
  936        * @throws IOException
  937        *
  938        * @since 0.2.0
  939        */
  940       public void quit() throws IOException {
  941           sftp.close();
  942       }
  943   
  944       /**
  945        *
  946        *
  947        * @param localdir
  948        * @param remotedir
  949        * @param recurse
  950        * @param sync
  951        * @param commit
  952        * @param progress
  953        *
  954        * @return
  955        *
  956        * @throws IOException
  957        */
  958       public DirectoryOperation copyLocalDirectory(String localdir,
  959           String remotedir, boolean recurse, boolean sync, boolean commit,
  960           FileTransferProgress progress) throws IOException {
  961           DirectoryOperation op = new DirectoryOperation();
  962   
  963           // Record the previous
  964           String pwd = pwd();
  965           String lpwd = lpwd();
  966           File local = resolveLocalPath(localdir);
  967           remotedir = resolveRemotePath(remotedir);
  968           remotedir += (remotedir.endsWith("/") ? "" : "/");
  969           remotedir += local.getName();
  970           remotedir += (remotedir.endsWith("/") ? "" : "/");
  971   
  972           // Setup the remote directory if were committing
  973           if (commit) {
  974               try {
  975                   FileAttributes attrs = stat(remotedir);
  976               } catch (IOException ex) {
  977                   mkdir(remotedir);
  978               }
  979           }
  980   
  981           // List the local files and verify against the remote server
  982           File[] ls = local.listFiles();
  983   
  984           if (ls != null) {
  985               for (int i = 0; i < ls.length; i++) {
  986                   if (ls[i].isDirectory() && !ls[i].getName().equals(".") &&
  987                           !ls[i].getName().equals("..")) {
  988                       if (recurse) {
  989                           File f = new File(local, ls[i].getName());
  990                           op.addDirectoryOperation(copyLocalDirectory(
  991                                   f.getAbsolutePath(), remotedir, recurse, sync,
  992                                   commit, progress), f);
  993                       }
  994                   } else if (ls[i].isFile()) {
  995                       try {
  996                           FileAttributes attrs = stat(remotedir +
  997                                   ls[i].getName());
  998   
  999                           if ((ls[i].length() == attrs.getSize().longValue()) &&
 1000                                   ((ls[i].lastModified() / 1000) == attrs.getModifiedTime()
 1001                                                                              .longValue())) {
 1002                               op.addUnchangedFile(ls[i]);
 1003                           } else {
 1004                               op.addUpdatedFile(ls[i]);
 1005                           }
 1006                       } catch (IOException ex1) {
 1007                           op.addNewFile(ls[i]);
 1008                       }
 1009   
 1010                       if (commit) {
 1011                           put(ls[i].getAbsolutePath(),
 1012                               remotedir + ls[i].getName(), progress);
 1013   
 1014                           FileAttributes attrs = stat(remotedir +
 1015                                   ls[i].getName());
 1016                           attrs.setTimes(new UnsignedInteger32(
 1017                                   ls[i].lastModified() / 1000),
 1018                               new UnsignedInteger32(ls[i].lastModified() / 1000));
 1019                           sftp.setAttributes(remotedir + ls[i].getName(), attrs);
 1020                       }
 1021                   }
 1022               }
 1023           }
 1024   
 1025           if (sync) {
 1026               // List the contents of the new local directory and remove any
 1027               // files/directories that were not updated
 1028               try {
 1029                   List files = ls(remotedir);
 1030                   SftpFile file;
 1031                   File f;
 1032   
 1033                   for (Iterator it = files.iterator(); it.hasNext();) {
 1034                       file = (SftpFile) it.next();
 1035   
 1036                       // Create a local file object to test for its existence
 1037                       f = new File(local, file.getFilename());
 1038   
 1039                       if (!op.containsFile(file) &&
 1040                               !file.getFilename().equals(".") &&
 1041                               !file.getFilename().equals("..")) {
 1042                           op.addDeletedFile(file);
 1043   
 1044                           if (commit) {
 1045                               if (file.isDirectory()) {
 1046                                   // Recurse through the directory, deleting stuff
 1047                                   recurseMarkForDeletion(file, op);
 1048   
 1049                                   if (commit) {
 1050                                       rm(file.getAbsolutePath(), true, true);
 1051                                   }
 1052                               } else if (file.isFile()) {
 1053                                   rm(file.getAbsolutePath());
 1054                               }
 1055                           }
 1056                       }
 1057                   }
 1058               } catch (IOException ex2) {
 1059                   // Ignorew since if it does not exist we cant delete it
 1060               }
 1061           }
 1062   
 1063           // Return the operation details
 1064           return op;
 1065       }
 1066   
 1067       /**
 1068        *
 1069        *
 1070        * @param eventListener
 1071        */
 1072       public void addEventListener(ChannelEventListener eventListener) {
 1073           sftp.addEventListener(eventListener);
 1074       }
 1075   
 1076       private void recurseMarkForDeletion(SftpFile file, DirectoryOperation op)
 1077           throws IOException {
 1078           List list = ls(file.getAbsolutePath());
 1079           op.addDeletedFile(file);
 1080   
 1081           for (Iterator it = list.iterator(); it.hasNext();) {
 1082               file = (SftpFile) it.next();
 1083   
 1084               if (file.isDirectory() && !file.getFilename().equals(".") &&
 1085                       !file.getFilename().equals("..")) {
 1086                   recurseMarkForDeletion(file, op);
 1087               } else if (file.isFile()) {
 1088                   op.addDeletedFile(file);
 1089               }
 1090           }
 1091       }
 1092   
 1093       private void recurseMarkForDeletion(File file, DirectoryOperation op)
 1094           throws IOException {
 1095           File[] list = file.listFiles();
 1096           op.addDeletedFile(file);
 1097   
 1098           if (list != null) {
 1099               for (int i = 0; i < list.length; i++) {
 1100                   file = list[i];
 1101   
 1102                   if (file.isDirectory() && !file.getName().equals(".") &&
 1103                           !file.getName().equals("..")) {
 1104                       recurseMarkForDeletion(file, op);
 1105                   } else if (file.isFile()) {
 1106                       op.addDeletedFile(file);
 1107                   }
 1108               }
 1109           }
 1110       }
 1111   
 1112       /**
 1113        *
 1114        *
 1115        * @param remotedir
 1116        * @param localdir
 1117        * @param recurse
 1118        * @param sync
 1119        * @param commit
 1120        * @param progress
 1121        *
 1122        * @return
 1123        *
 1124        * @throws IOException
 1125        */
 1126       public DirectoryOperation copyRemoteDirectory(String remotedir,
 1127           String localdir, boolean recurse, boolean sync, boolean commit,
 1128           FileTransferProgress progress) throws IOException {
 1129           // Create an operation object to hold the information
 1130           DirectoryOperation op = new DirectoryOperation();
 1131   
 1132           // Record the previous working directoies
 1133           String pwd = pwd();
 1134           String lpwd = lpwd();
 1135           cd(remotedir);
 1136   
 1137           // Setup the local cwd
 1138           String base = remotedir;
 1139           int idx = base.lastIndexOf('/');
 1140   
 1141           if (idx != -1) {
 1142               base = base.substring(idx + 1);
 1143           }
 1144   
 1145           File local = new File(localdir, base);
 1146   
 1147           //				File local = new File(localdir, remotedir);
 1148           if (!local.isAbsolute()) {
 1149               local = new File(lpwd(), localdir);
 1150           }
 1151   
 1152           if (!local.exists() && commit) {
 1153               local.mkdir();
 1154           }
 1155   
 1156           List files = ls();
 1157           SftpFile file;
 1158           File f;
 1159   
 1160           for (Iterator it = files.iterator(); it.hasNext();) {
 1161               file = (SftpFile) it.next();
 1162   
 1163               if (file.isDirectory() && !file.getFilename().equals(".") &&
 1164                       !file.getFilename().equals("..")) {
 1165                   if (recurse) {
 1166                       f = new File(local, file.getFilename());
 1167                       op.addDirectoryOperation(copyRemoteDirectory(
 1168                               file.getFilename(), local.getAbsolutePath(),
 1169                               recurse, sync, commit, progress), f);
 1170                   }
 1171               } else if (file.isFile()) {
 1172                   f = new File(local, file.getFilename());
 1173   
 1174                   if (f.exists() &&
 1175                           (f.length() == file.getAttributes().getSize().longValue()) &&
 1176                           ((f.lastModified() / 1000) == file.getAttributes()
 1177                                                                 .getModifiedTime()
 1178                                                                 .longValue())) {
 1179                       if (commit) {
 1180                           op.addUnchangedFile(f);
 1181                       } else {
 1182                           op.addUnchangedFile(file);
 1183                       }
 1184   
 1185                       continue;
 1186                   }
 1187   
 1188                   if (f.exists()) {
 1189                       if (commit) {
 1190                           op.addUpdatedFile(f);
 1191                       } else {
 1192                           op.addUpdatedFile(file);
 1193                       }
 1194                   } else {
 1195                       if (commit) {
 1196                           op.addNewFile(f);
 1197                       } else {
 1198                           op.addNewFile(file);
 1199                       }
 1200                   }
 1201   
 1202                   if (commit) {
 1203                       FileAttributes attrs = get(file.getFilename(),
 1204                               f.getAbsolutePath(), progress);
 1205                       f.setLastModified(attrs.getModifiedTime().longValue() * 1000);
 1206                   }
 1207               }
 1208           }
 1209   
 1210           if (sync) {
 1211               // List the contents of the new local directory and remove any
 1212               // files/directories that were not updated
 1213               File[] contents = local.listFiles();
 1214   
 1215               if (contents != null) {
 1216                   for (int i = 0; i < contents.length; i++) {
 1217                       if (!op.containsFile(contents[i])) {
 1218                           op.addDeletedFile(contents[i]);
 1219   
 1220                           if (contents[i].isDirectory() &&
 1221                                   !contents[i].getName().equals(".") &&
 1222                                   !contents[i].getName().equals("..")) {
 1223                               recurseMarkForDeletion(contents[i], op);
 1224   
 1225                               if (commit) {
 1226                                   IOUtil.recurseDeleteDirectory(contents[i]);
 1227                               }
 1228                           } else if (commit) {
 1229                               contents[i].delete();
 1230                           }
 1231                       }
 1232                   }
 1233               }
 1234           }
 1235   
 1236           cd(pwd);
 1237   
 1238           return op;
 1239       }
 1240   }

Save This Page
Home » j2ssh-0.2.9-src » com.sshtools.j2ssh » [javadoc | source]