[BACK]Return to sftp-int.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Diff for /src/usr.bin/ssh/Attic/sftp-int.c between version 1.40.2.4 and 1.41

version 1.40.2.4, 2002/10/11 14:53:07 version 1.41, 2001/12/19 07:18:56
Line 1 
Line 1 
 /*  /*
  * Copyright (c) 2001,2002 Damien Miller.  All rights reserved.   * Copyright (c) 2001 Damien Miller.  All rights reserved.
  *   *
  * Redistribution and use in source and binary forms, with or without   * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions   * modification, are permitted provided that the following conditions
Line 22 
Line 22 
  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */   */
   
   /* XXX: globbed ls */
 /* XXX: recursive operations */  /* XXX: recursive operations */
   
 #include "includes.h"  #include "includes.h"
Line 43 
Line 44 
 /* File to read commands from */  /* File to read commands from */
 extern FILE *infile;  extern FILE *infile;
   
 /* Size of buffer used when copying files */  /* Version of server we are speaking to */
 extern size_t copy_buffer_len;  int version;
   
 /* Number of concurrent outstanding requests */  
 extern int num_requests;  
   
 /* Seperators for interactive commands */  /* Seperators for interactive commands */
 #define WHITESPACE " \t\r\n"  #define WHITESPACE " \t\r\n"
   
Line 177 
Line 175 
                     strerror(errno));                      strerror(errno));
                 _exit(1);                  _exit(1);
         }          }
         while (waitpid(pid, &status, 0) == -1)          if (waitpid(pid, &status, 0) == -1)
                 if (errno != EINTR)                  fatal("Couldn't wait for child: %s", strerror(errno));
                         fatal("Couldn't wait for child: %s", strerror(errno));  
         if (!WIFEXITED(status))          if (!WIFEXITED(status))
                 error("Shell exited abormally");                  error("Shell exited abormally");
         else if (WEXITSTATUS(status))          else if (WEXITSTATUS(status))
Line 202 
Line 199 
         }          }
 }  }
   
 /* Strip one path (usually the pwd) from the start of another */  
 static char *  static char *
 path_strip(char *path, char *strip)  
 {  
         size_t len;  
   
         if (strip == NULL)  
                 return (xstrdup(path));  
   
         len = strlen(strip);  
         if (strip != NULL && strncmp(path, strip, len) == 0) {  
                 if (strip[len - 1] != '/' && path[len] == '/')  
                         len++;  
                 return (xstrdup(path + len));  
         }  
   
         return (xstrdup(path));  
 }  
   
 static char *  
 path_append(char *p1, char *p2)  path_append(char *p1, char *p2)
 {  {
         char *ret;          char *ret;
Line 229 
Line 207 
   
         ret = xmalloc(len);          ret = xmalloc(len);
         strlcpy(ret, p1, len);          strlcpy(ret, p1, len);
         if (p1[strlen(p1) - 1] != '/')          if (strcmp(p1, "/") != 0)
                 strlcat(ret, "/", len);                  strlcat(ret, "/", len);
         strlcat(ret, p2, len);          strlcat(ret, p2, len);
   
Line 294 
Line 272 
 }  }
   
 static int  static int
 parse_ls_flags(const char **cpp, int *lflag)  
 {  
         const char *cp = *cpp;  
   
         /* Check for flags */  
         if (cp++[0] == '-') {  
                 for(; strchr(WHITESPACE, *cp) == NULL; cp++) {  
                         switch (*cp) {  
                         case 'l':  
                                 *lflag = 1;  
                                 break;  
                         default:  
                                 error("Invalid flag -%c", *cp);  
                                 return(-1);  
                         }  
                 }  
                 *cpp = cp + strspn(cp, WHITESPACE);  
         }  
   
         return(0);  
 }  
   
 static int  
 get_pathname(const char **cpp, char **path)  get_pathname(const char **cpp, char **path)
 {  {
         const char *cp = *cpp, *end;          const char *cp = *cpp, *end;
Line 377 
Line 332 
 }  }
   
 static int  static int
 remote_is_dir(struct sftp_conn *conn, char *path)  remote_is_dir(int in, int out, char *path)
 {  {
         Attrib *a;          Attrib *a;
   
         /* XXX: report errors? */          /* XXX: report errors? */
         if ((a = do_stat(conn, path, 1)) == NULL)          if ((a = do_stat(in, out, path, 1)) == NULL)
                 return(0);                  return(0);
         if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))          if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
                 return(0);                  return(0);
Line 390 
Line 345 
 }  }
   
 static int  static int
 process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)  process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
 {  {
         char *abs_src = NULL;          char *abs_src = NULL;
         char *abs_dst = NULL;          char *abs_dst = NULL;
Line 404 
Line 359 
   
         memset(&g, 0, sizeof(g));          memset(&g, 0, sizeof(g));
         debug3("Looking up %s", abs_src);          debug3("Looking up %s", abs_src);
         if (remote_glob(conn, abs_src, 0, NULL, &g)) {          if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
                 error("File \"%s\" not found.", abs_src);                  error("File \"%s\" not found.", abs_src);
                 err = -1;                  err = -1;
                 goto out;                  goto out;
Line 428 
Line 383 
                         goto out;                          goto out;
                 }                  }
                 printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);                  printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
                 err = do_download(conn, g.gl_pathv[0], abs_dst, pflag);                  err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
                 goto out;                  goto out;
         }          }
   
Line 452 
Line 407 
                         abs_dst = tmp;                          abs_dst = tmp;
   
                 printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);                  printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
                 if (do_download(conn, g.gl_pathv[i], abs_dst, pflag) == -1)                  if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
                         err = -1;                          err = -1;
                 xfree(abs_dst);                  xfree(abs_dst);
                 abs_dst = NULL;                  abs_dst = NULL;
Line 467 
Line 422 
 }  }
   
 static int  static int
 process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)  process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
 {  {
         char *tmp_dst = NULL;          char *tmp_dst = NULL;
         char *abs_dst = NULL;          char *abs_dst = NULL;
Line 493 
Line 448 
         if (g.gl_pathv[0] && g.gl_matchc == 1) {          if (g.gl_pathv[0] && g.gl_matchc == 1) {
                 if (tmp_dst) {                  if (tmp_dst) {
                         /* If directory specified, append filename */                          /* If directory specified, append filename */
                         if (remote_is_dir(conn, tmp_dst)) {                          if (remote_is_dir(in, out, tmp_dst)) {
                                 if (infer_path(g.gl_pathv[0], &tmp)) {                                  if (infer_path(g.gl_pathv[0], &tmp)) {
                                         err = 1;                                          err = 1;
                                         goto out;                                          goto out;
Line 510 
Line 465 
                         abs_dst = make_absolute(abs_dst, pwd);                          abs_dst = make_absolute(abs_dst, pwd);
                 }                  }
                 printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);                  printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
                 err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag);                  err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
                 goto out;                  goto out;
         }          }
   
         /* Multiple matches, dst may be directory or unspecified */          /* Multiple matches, dst may be directory or unspecified */
         if (tmp_dst && !remote_is_dir(conn, tmp_dst)) {          if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
                 error("Multiple files match, but \"%s\" is not a directory",                  error("Multiple files match, but \"%s\" is not a directory",
                     tmp_dst);                      tmp_dst);
                 err = -1;                  err = -1;
Line 534 
Line 489 
                         abs_dst = make_absolute(tmp, pwd);                          abs_dst = make_absolute(tmp, pwd);
   
                 printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);                  printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
                 if (do_upload(conn, g.gl_pathv[i], abs_dst, pflag) == -1)                  if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
                         err = -1;                          err = -1;
         }          }
   
Line 547 
Line 502 
 }  }
   
 static int  static int
 sdirent_comp(const void *aa, const void *bb)  parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
       char **path1, char **path2)
 {  {
         SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;  
         SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;  
   
         return (strcmp(a->filename, b->filename));  
 }  
   
 /* sftp ls.1 replacement for directories */  
 static int  
 do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)  
 {  
         int n;  
         SFTP_DIRENT **d;  
   
         if ((n = do_readdir(conn, path, &d)) != 0)  
                 return (n);  
   
         /* Count entries for sort */  
         for (n = 0; d[n] != NULL; n++)  
                 ;  
   
         qsort(d, n, sizeof(*d), sdirent_comp);  
   
         for (n = 0; d[n] != NULL; n++) {  
                 char *tmp, *fname;  
   
                 tmp = path_append(path, d[n]->filename);  
                 fname = path_strip(tmp, strip_path);  
                 xfree(tmp);  
   
                 if (lflag) {  
                         char *lname;  
                         struct stat sb;  
   
                         memset(&sb, 0, sizeof(sb));  
                         attrib_to_stat(&d[n]->a, &sb);  
                         lname = ls_file(fname, &sb, 1);  
                         printf("%s\n", lname);  
                         xfree(lname);  
                 } else {  
                         /* XXX - multicolumn display would be nice here */  
                         printf("%s\n", fname);  
                 }  
   
                 xfree(fname);  
         }  
   
         free_sftp_dirents(d);  
         return (0);  
 }  
   
 /* sftp ls.1 replacement which handles path globs */  
 static int  
 do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,  
     int lflag)  
 {  
         glob_t g;  
         int i;  
         Attrib *a;  
         struct stat sb;  
   
         memset(&g, 0, sizeof(g));  
   
         if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,  
             NULL, &g)) {  
                 error("Can't ls: \"%s\" not found", path);  
                 return (-1);  
         }  
   
         /*  
          * If the glob returns a single match, which is the same as the  
          * input glob, and it is a directory, then just list its contents  
          */  
         if (g.gl_pathc == 1 &&  
             strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) {  
                 if ((a = do_lstat(conn, path, 1)) == NULL) {  
                         globfree(&g);  
                         return (-1);  
                 }  
                 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&  
                     S_ISDIR(a->perm)) {  
                         globfree(&g);  
                         return (do_ls_dir(conn, path, strip_path, lflag));  
                 }  
         }  
   
         for (i = 0; g.gl_pathv[i]; i++) {  
                 char *fname, *lname;  
   
                 fname = path_strip(g.gl_pathv[i], strip_path);  
   
                 if (lflag) {  
                         /*  
                          * XXX: this is slow - 1 roundtrip per path  
                          * A solution to this is to fork glob() and  
                          * build a sftp specific version which keeps the  
                          * attribs (which currently get thrown away)  
                          * that the server returns as well as the filenames.  
                          */  
                         memset(&sb, 0, sizeof(sb));  
                         a = do_lstat(conn, g.gl_pathv[i], 1);  
                         if (a != NULL)  
                                 attrib_to_stat(a, &sb);  
                         lname = ls_file(fname, &sb, 1);  
                         printf("%s\n", lname);  
                         xfree(lname);  
                 } else {  
                         /* XXX - multicolumn display would be nice here */  
                         printf("%s\n", fname);  
                 }  
                 xfree(fname);  
         }  
   
         if (g.gl_pathc)  
                 globfree(&g);  
   
         return (0);  
 }  
   
 static int  
 parse_args(const char **cpp, int *pflag, int *lflag,  
     unsigned long *n_arg, char **path1, char **path2)  
 {  
         const char *cmd, *cp = *cpp;          const char *cmd, *cp = *cpp;
         char *cp2;          char *cp2;
         int base = 0;          int base = 0;
Line 709 
Line 543 
         }          }
   
         /* Get arguments and parse flags */          /* Get arguments and parse flags */
         *lflag = *pflag = *n_arg = 0;          *pflag = *n_arg = 0;
         *path1 = *path2 = NULL;          *path1 = *path2 = NULL;
         switch (cmdnum) {          switch (cmdnum) {
         case I_GET:          case I_GET:
Line 756 
Line 590 
                 }                  }
                 break;                  break;
         case I_LS:          case I_LS:
                 if (parse_ls_flags(&cp, lflag))  
                         return(-1);  
                 /* Path is optional */                  /* Path is optional */
                 if (get_pathname(&cp, path1))                  if (get_pathname(&cp, path1))
                         return(-1);                          return(-1);
Line 815 
Line 647 
 }  }
   
 static int  static int
 parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)  parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
 {  {
         char *path1, *path2, *tmp;          char *path1, *path2, *tmp;
         int pflag, lflag, cmdnum, i;          int pflag, cmdnum, i;
         unsigned long n_arg;          unsigned long n_arg;
         Attrib a, *aa;          Attrib a, *aa;
         char path_buf[MAXPATHLEN];          char path_buf[MAXPATHLEN];
Line 826 
Line 658 
         glob_t g;          glob_t g;
   
         path1 = path2 = NULL;          path1 = path2 = NULL;
         cmdnum = parse_args(&cmd, &pflag, &lflag, &n_arg,          cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
             &path1, &path2);  
   
         memset(&g, 0, sizeof(g));          memset(&g, 0, sizeof(g));
   
Line 836 
Line 667 
         case -1:          case -1:
                 break;                  break;
         case I_GET:          case I_GET:
                 err = process_get(conn, path1, path2, *pwd, pflag);                  err = process_get(in, out, path1, path2, *pwd, pflag);
                 break;                  break;
         case I_PUT:          case I_PUT:
                 err = process_put(conn, path1, path2, *pwd, pflag);                  err = process_put(in, out, path1, path2, *pwd, pflag);
                 break;                  break;
         case I_RENAME:          case I_RENAME:
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 path2 = make_absolute(path2, *pwd);                  path2 = make_absolute(path2, *pwd);
                 err = do_rename(conn, path1, path2);                  err = do_rename(in, out, path1, path2);
                 break;                  break;
         case I_SYMLINK:          case I_SYMLINK:
                 path2 = make_absolute(path2, *pwd);                  if (version < 3) {
                 err = do_symlink(conn, path1, path2);                          error("The server (version %d) does not support "
                               "this operation", version);
                           err = -1;
                   } else {
                           path2 = make_absolute(path2, *pwd);
                           err = do_symlink(in, out, path1, path2);
                   }
                 break;                  break;
         case I_RM:          case I_RM:
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         printf("Removing %s\n", g.gl_pathv[i]);                          printf("Removing %s\n", g.gl_pathv[i]);
                         if (do_rm(conn, g.gl_pathv[i]) == -1)                          if (do_rm(in, out, g.gl_pathv[i]) == -1)
                                 err = -1;                                  err = -1;
                 }                  }
                 break;                  break;
Line 864 
Line 701 
                 attrib_clear(&a);                  attrib_clear(&a);
                 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;                  a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
                 a.perm = 0777;                  a.perm = 0777;
                 err = do_mkdir(conn, path1, &a);                  err = do_mkdir(in, out, path1, &a);
                 break;                  break;
         case I_RMDIR:          case I_RMDIR:
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 err = do_rmdir(conn, path1);                  err = do_rmdir(in, out, path1);
                 break;                  break;
         case I_CHDIR:          case I_CHDIR:
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 if ((tmp = do_realpath(conn, path1)) == NULL) {                  if ((tmp = do_realpath(in, out, path1)) == NULL) {
                         err = 1;                          err = 1;
                         break;                          break;
                 }                  }
                 if ((aa = do_stat(conn, tmp, 0)) == NULL) {                  if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
                         xfree(tmp);                          xfree(tmp);
                         err = 1;                          err = 1;
                         break;                          break;
Line 899 
Line 736 
                 break;                  break;
         case I_LS:          case I_LS:
                 if (!path1) {                  if (!path1) {
                         do_globbed_ls(conn, *pwd, *pwd, lflag);                          do_ls(in, out, *pwd);
                         break;                          break;
                 }                  }
   
                 /* Strip pwd off beginning of non-absolute paths */  
                 tmp = NULL;  
                 if (*path1 != '/')  
                         tmp = *pwd;  
   
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                   if ((tmp = do_realpath(in, out, path1)) == NULL)
                 do_globbed_ls(conn, path1, tmp, lflag);                          break;
                   xfree(path1);
                   path1 = tmp;
                   if ((aa = do_stat(in, out, path1, 0)) == NULL)
                           break;
                   if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
                       !S_ISDIR(aa->perm)) {
                           error("Can't ls: \"%s\" is not a directory", path1);
                           break;
                   }
                   do_ls(in, out, path1);
                 break;                  break;
         case I_LCHDIR:          case I_LCHDIR:
                 if (chdir(path1) == -1) {                  if (chdir(path1) == -1) {
Line 941 
Line 782 
                 attrib_clear(&a);                  attrib_clear(&a);
                 a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;                  a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
                 a.perm = n_arg;                  a.perm = n_arg;
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         printf("Changing mode on %s\n", g.gl_pathv[i]);                          printf("Changing mode on %s\n", g.gl_pathv[i]);
                         do_setstat(conn, g.gl_pathv[i], &a);                          do_setstat(in, out, g.gl_pathv[i], &a);
                 }                  }
                 break;                  break;
         case I_CHOWN:          case I_CHOWN:
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         if (!(aa = do_stat(conn, g.gl_pathv[i], 0)))                          if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
                                 continue;                                  continue;
                         if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {                          if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
                                 error("Can't get current ownership of "                                  error("Can't get current ownership of "
Line 961 
Line 802 
                         printf("Changing owner on %s\n", g.gl_pathv[i]);                          printf("Changing owner on %s\n", g.gl_pathv[i]);
                         aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;                          aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
                         aa->uid = n_arg;                          aa->uid = n_arg;
                         do_setstat(conn, g.gl_pathv[i], aa);                          do_setstat(in, out, g.gl_pathv[i], aa);
                 }                  }
                 break;                  break;
         case I_CHGRP:          case I_CHGRP:
                 path1 = make_absolute(path1, *pwd);                  path1 = make_absolute(path1, *pwd);
                 remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);                  remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
                 for (i = 0; g.gl_pathv[i]; i++) {                  for (i = 0; g.gl_pathv[i]; i++) {
                         if (!(aa = do_stat(conn, g.gl_pathv[i], 0)))                          if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
                                 continue;                                  continue;
                         if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {                          if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
                                 error("Can't get current ownership of "                                  error("Can't get current ownership of "
Line 978 
Line 819 
                         printf("Changing group on %s\n", g.gl_pathv[i]);                          printf("Changing group on %s\n", g.gl_pathv[i]);
                         aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;                          aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
                         aa->gid = n_arg;                          aa->gid = n_arg;
                         do_setstat(conn, g.gl_pathv[i], aa);                          do_setstat(in, out, g.gl_pathv[i], aa);
                 }                  }
                 break;                  break;
         case I_PWD:          case I_PWD:
Line 998 
Line 839 
                 help();                  help();
                 break;                  break;
         case I_VERSION:          case I_VERSION:
                 printf("SFTP protocol version %u\n", sftp_proto_version(conn));                  printf("SFTP protocol version %d\n", version);
                 break;                  break;
         default:          default:
                 fatal("%d is not implemented", cmdnum);                  fatal("%d is not implemented", cmdnum);
Line 1024 
Line 865 
         char *pwd;          char *pwd;
         char *dir = NULL;          char *dir = NULL;
         char cmd[2048];          char cmd[2048];
         struct sftp_conn *conn;  
   
         conn = do_init(fd_in, fd_out, copy_buffer_len, num_requests);          version = do_init(fd_in, fd_out);
         if (conn == NULL)          if (version == -1)
                 fatal("Couldn't initialise connection to server");                  fatal("Couldn't initialise connection to server");
   
         pwd = do_realpath(conn, ".");          pwd = do_realpath(fd_in, fd_out, ".");
         if (pwd == NULL)          if (pwd == NULL)
                 fatal("Need cwd");                  fatal("Need cwd");
   
Line 1038 
Line 878 
                 dir = xstrdup(file1);                  dir = xstrdup(file1);
                 dir = make_absolute(dir, pwd);                  dir = make_absolute(dir, pwd);
   
                 if (remote_is_dir(conn, dir) && file2 == NULL) {                  if (remote_is_dir(fd_in, fd_out, dir) && file2 == NULL) {
                         printf("Changing to: %s\n", dir);                          printf("Changing to: %s\n", dir);
                         snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);                          snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
                         parse_dispatch_command(conn, cmd, &pwd);                          parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
                 } else {                  } else {
                         if (file2 == NULL)                          if (file2 == NULL)
                                 snprintf(cmd, sizeof cmd, "get %s", dir);                                  snprintf(cmd, sizeof cmd, "get %s", dir);
Line 1049 
Line 889 
                                 snprintf(cmd, sizeof cmd, "get %s %s", dir,                                  snprintf(cmd, sizeof cmd, "get %s %s", dir,
                                     file2);                                      file2);
   
                         parse_dispatch_command(conn, cmd, &pwd);                          parse_dispatch_command(fd_in, fd_out, cmd, &pwd);
                         xfree(dir);  
                         return;                          return;
                 }                  }
                 xfree(dir);  
         }          }
         setvbuf(stdout, NULL, _IOLBF, 0);          setvbuf(stdout, NULL, _IOLBF, 0);
         setvbuf(infile, NULL, _IOLBF, 0);          setvbuf(infile, NULL, _IOLBF, 0);
Line 1074 
Line 912 
                 if (cp)                  if (cp)
                         *cp = '\0';                          *cp = '\0';
   
                 if (parse_dispatch_command(conn, cmd, &pwd))                  if (parse_dispatch_command(fd_in, fd_out, cmd, &pwd))
                         break;                          break;
         }          }
         xfree(pwd);          xfree(pwd);

Legend:
Removed from v.1.40.2.4  
changed lines
  Added in v.1.41