]> andersk Git - openssh.git/blobdiff - sftp-int.c
[configure.ac] Make sure -lcrypto is before -lsocket for sco3. ok mouring@
[openssh.git] / sftp-int.c
index 88b0530ab94c7c7ba32e89b22eb4a4f85507df6e..3ee57515dcba371ce0da3bc63b29622ed3bbfe23 100644 (file)
@@ -25,7 +25,7 @@
 /* XXX: recursive operations */
 
 #include "includes.h"
-RCSID("$OpenBSD: sftp-int.c,v 1.52 2003/01/10 08:19:07 fgsch Exp $");
+RCSID("$OpenBSD: sftp-int.c,v 1.67 2004/01/23 17:57:48 mouring Exp $");
 
 #include "buffer.h"
 #include "xmalloc.h"
@@ -41,6 +41,9 @@ RCSID("$OpenBSD: sftp-int.c,v 1.52 2003/01/10 08:19:07 fgsch Exp $");
 /* File to read commands from */
 extern FILE *infile;
 
+/* Are we in batchfile mode? */
+extern int batchmode;
+
 /* Size of buffer used when copying files */
 extern size_t copy_buffer_len;
 
@@ -50,9 +53,13 @@ extern int num_requests;
 /* This is set to 0 if the progressmeter is not desired. */
 int showprogress = 1;
 
-/* Seperators for interactive commands */
+/* Separators for interactive commands */
 #define WHITESPACE " \t\r\n"
 
+/* Define what type of ls view (0 - multi-column) */
+#define LONG_VIEW 1            /* Full view ala ls -l */
+#define SHORT_VIEW 2           /* Single row view ala ls -1 */
+
 /* Commands for interactive mode */
 #define I_CHDIR                1
 #define I_CHGRP                2
@@ -83,7 +90,7 @@ struct CMD {
        const int n;
 };
 
-const struct CMD cmds[] = {
+static const struct CMD cmds[] = {
        { "bye",        I_QUIT },
        { "cd",         I_CHDIR },
        { "chdir",      I_CHDIR },
@@ -137,7 +144,7 @@ help(void)
        printf("ls [path]                     Display remote directory listing\n");
        printf("lumask umask                  Set local umask to 'umask'\n");
        printf("mkdir path                    Create remote directory\n");
-       printf("preogress                     Toggle display of progress meter\n");
+       printf("progress                      Toggle display of progress meter\n");
        printf("put local-path [remote-path]  Upload file\n");
        printf("pwd                           Display remote working directory\n");
        printf("exit                          Quit sftp\n");
@@ -307,7 +314,10 @@ parse_ls_flags(const char **cpp, int *lflag)
                for(; strchr(WHITESPACE, *cp) == NULL; cp++) {
                        switch (*cp) {
                        case 'l':
-                               *lflag = 1;
+                               *lflag = LONG_VIEW;
+                               break;
+                       case '1':
+                               *lflag = SHORT_VIEW;
                                break;
                        default:
                                error("Invalid flag -%c", *cp);
@@ -325,7 +335,7 @@ get_pathname(const char **cpp, char **path)
 {
        const char *cp = *cpp, *end;
        char quot;
-       int i;
+       int i, j;
 
        cp += strspn(cp, WHITESPACE);
        if (!*cp) {
@@ -334,36 +344,54 @@ get_pathname(const char **cpp, char **path)
                return (0);
        }
 
+       *path = xmalloc(strlen(cp) + 1);
+
        /* Check for quoted filenames */
        if (*cp == '\"' || *cp == '\'') {
                quot = *cp++;
 
-               end = strchr(cp, quot);
-               if (end == NULL) {
-                       error("Unterminated quote");
-                       goto fail;
+               /* Search for terminating quote, unescape some chars */
+               for (i = j = 0; i <= strlen(cp); i++) {
+                       if (cp[i] == quot) {    /* Found quote */
+                               i++;
+                               (*path)[j] = '\0';
+                               break;
+                       }
+                       if (cp[i] == '\0') {    /* End of string */
+                               error("Unterminated quote");
+                               goto fail;
+                       }
+                       if (cp[i] == '\\') {    /* Escaped characters */
+                               i++;
+                               if (cp[i] != '\'' && cp[i] != '\"' &&
+                                   cp[i] != '\\') {
+                                       error("Bad escaped character '\%c'",
+                                           cp[i]);
+                                       goto fail;
+                               }
+                       }
+                       (*path)[j++] = cp[i];
                }
-               if (cp == end) {
+
+               if (j == 0) {
                        error("Empty quotes");
                        goto fail;
                }
-               *cpp = end + 1 + strspn(end + 1, WHITESPACE);
+               *cpp = cp + i + strspn(cp + i, WHITESPACE);
        } else {
                /* Read to end of filename */
                end = strpbrk(cp, WHITESPACE);
                if (end == NULL)
                        end = strchr(cp, '\0');
                *cpp = end + strspn(end, WHITESPACE);
-       }
-
-       i = end - cp;
 
-       *path = xmalloc(i + 1);
-       memcpy(*path, cp, i);
-       (*path)[i] = '\0';
-       return(0);
+               memcpy(*path, cp, end - cp);
+               (*path)[end - cp] = '\0';
+       }
+       return (0);
 
  fail:
+       xfree(*path);
        *path = NULL;
        return (-1);
 }
@@ -380,6 +408,17 @@ is_dir(char *path)
        return(sb.st_mode & S_IFDIR);
 }
 
+static int
+is_reg(char *path)
+{
+       struct stat sb;
+
+       if (stat(path, &sb) == -1)
+               fatal("stat %s: %s", path, strerror(errno));
+
+       return(S_ISREG(sb.st_mode));
+}
+
 static int
 remote_is_dir(struct sftp_conn *conn, char *path)
 {
@@ -414,29 +453,8 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
                goto out;
        }
 
-       /* Only one match, dst may be file, directory or unspecified */
-       if (g.gl_pathv[0] && g.gl_matchc == 1) {
-               if (dst) {
-                       /* If directory specified, append filename */
-                       if (is_dir(dst)) {
-                               if (infer_path(g.gl_pathv[0], &tmp)) {
-                                       err = 1;
-                                       goto out;
-                               }
-                               abs_dst = path_append(dst, tmp);
-                               xfree(tmp);
-                       } else
-                               abs_dst = xstrdup(dst);
-               } else if (infer_path(g.gl_pathv[0], &abs_dst)) {
-                       err = -1;
-                       goto out;
-               }
-               err = do_download(conn, g.gl_pathv[0], abs_dst, pflag);
-               goto out;
-       }
-
-       /* Multiple matches, dst may be directory or unspecified */
-       if (dst && !is_dir(dst)) {
+       /* If multiple matches, dst must be a directory or unspecified */
+       if (g.gl_matchc > 1 && dst && !is_dir(dst)) {
                error("Multiple files match, but \"%s\" is not a directory",
                    dst);
                err = -1;
@@ -448,7 +466,19 @@ process_get(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
                        err = -1;
                        goto out;
                }
-               if (dst) {
+
+               if (g.gl_matchc == 1 && dst) {
+                       /* If directory specified, append filename */
+                       if (is_dir(dst)) {
+                               if (infer_path(g.gl_pathv[0], &tmp)) {
+                                       err = 1;
+                                       goto out;
+                               }
+                               abs_dst = path_append(dst, tmp);
+                               xfree(tmp);
+                       } else
+                               abs_dst = xstrdup(dst);
+               } else if (dst) {
                        abs_dst = path_append(dst, tmp);
                        xfree(tmp);
                } else
@@ -492,32 +522,8 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
                goto out;
        }
 
-       /* Only one match, dst may be file, directory or unspecified */
-       if (g.gl_pathv[0] && g.gl_matchc == 1) {
-               if (tmp_dst) {
-                       /* If directory specified, append filename */
-                       if (remote_is_dir(conn, tmp_dst)) {
-                               if (infer_path(g.gl_pathv[0], &tmp)) {
-                                       err = 1;
-                                       goto out;
-                               }
-                               abs_dst = path_append(tmp_dst, tmp);
-                               xfree(tmp);
-                       } else
-                               abs_dst = xstrdup(tmp_dst);
-               } else {
-                       if (infer_path(g.gl_pathv[0], &abs_dst)) {
-                               err = -1;
-                               goto out;
-                       }
-                       abs_dst = make_absolute(abs_dst, pwd);
-               }
-               err = do_upload(conn, g.gl_pathv[0], abs_dst, pflag);
-               goto out;
-       }
-
-       /* Multiple matches, dst may be directory or unspecified */
-       if (tmp_dst && !remote_is_dir(conn, tmp_dst)) {
+       /* If multiple matches, dst may be directory or unspecified */
+       if (g.gl_matchc > 1 && tmp_dst && !remote_is_dir(conn, tmp_dst)) {
                error("Multiple files match, but \"%s\" is not a directory",
                    tmp_dst);
                err = -1;
@@ -525,11 +531,29 @@ process_put(struct sftp_conn *conn, char *src, char *dst, char *pwd, int pflag)
        }
 
        for (i = 0; g.gl_pathv[i]; i++) {
+               if (!is_reg(g.gl_pathv[i])) {
+                       error("skipping non-regular file %s",
+                           g.gl_pathv[i]);
+                       continue;
+               }
                if (infer_path(g.gl_pathv[i], &tmp)) {
                        err = -1;
                        goto out;
                }
-               if (tmp_dst) {
+
+               if (g.gl_matchc == 1 && tmp_dst) {
+                       /* If directory specified, append filename */
+                       if (remote_is_dir(conn, tmp_dst)) {
+                               if (infer_path(g.gl_pathv[0], &tmp)) {
+                                       err = 1;
+                                       goto out;
+                               }
+                               abs_dst = path_append(tmp_dst, tmp);
+                               xfree(tmp);
+                       } else
+                               abs_dst = xstrdup(tmp_dst);
+
+               } else if (tmp_dst) {
                        abs_dst = path_append(tmp_dst, tmp);
                        xfree(tmp);
                } else
@@ -545,6 +569,7 @@ out:
                xfree(abs_dst);
        if (tmp_dst)
                xfree(tmp_dst);
+       globfree(&g);
        return(err);
 }
 
@@ -561,15 +586,34 @@ sdirent_comp(const void *aa, const void *bb)
 static int
 do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
 {
-       int n;
+       int n, c = 1, colspace = 0, columns = 1;
        SFTP_DIRENT **d;
 
        if ((n = do_readdir(conn, path, &d)) != 0)
                return (n);
 
-       /* Count entries for sort */
-       for (n = 0; d[n] != NULL; n++)
-               ;
+       if (!(lflag & SHORT_VIEW)) {
+               int m = 0, width = 80;
+               struct winsize ws;
+               char *tmp;
+
+               /* Count entries for sort and find longest filename */
+               for (n = 0; d[n] != NULL; n++)
+                       m = MAX(m, strlen(d[n]->filename));
+
+               /* Add any subpath that also needs to be counted */
+               tmp = path_strip(path, strip_path);
+               m += strlen(tmp);
+               xfree(tmp);
+
+               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
+                       width = ws.ws_col;
+
+               columns = width / (m + 2);
+               columns = MAX(columns, 1);
+               colspace = width / columns;
+               colspace = MIN(colspace, width);
+       }
 
        qsort(d, n, sizeof(*d), sdirent_comp);
 
@@ -580,7 +624,7 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
                fname = path_strip(tmp, strip_path);
                xfree(tmp);
 
-               if (lflag) {
+               if (lflag & LONG_VIEW) {
                        char *lname;
                        struct stat sb;
 
@@ -590,13 +634,20 @@ do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
                        printf("%s\n", lname);
                        xfree(lname);
                } else {
-                       /* XXX - multicolumn display would be nice here */
-                       printf("%s\n", fname);
+                       printf("%-*s", colspace, fname);
+                       if (c >= columns) {
+                               printf("\n");
+                               c = 1;
+                       } else
+                               c++;
                }
 
                xfree(fname);
        }
 
+       if (!(lflag & LONG_VIEW) && (c != 1))
+               printf("\n");
+
        free_sftp_dirents(d);
        return (0);
 }
@@ -607,9 +658,8 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
     int lflag)
 {
        glob_t g;
-       int i;
+       int i, c = 1, colspace = 0, columns = 1;
        Attrib *a;
-       struct stat sb;
 
        memset(&g, 0, sizeof(g));
 
@@ -627,7 +677,7 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
            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);
+                       return (-1);
                }
                if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
                    S_ISDIR(a->perm)) {
@@ -636,12 +686,31 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
                }
        }
 
+       if (!(lflag & SHORT_VIEW)) {
+               int m = 0, width = 80;
+               struct winsize ws;
+
+               /* Count entries for sort and find longest filename */
+               for (i = 0; g.gl_pathv[i]; i++)
+                       m = MAX(m, strlen(g.gl_pathv[i]));
+
+               if (ioctl(fileno(stdin), TIOCGWINSZ, &ws) != -1)
+                       width = ws.ws_col;
+
+               columns = width / (m + 2);
+               columns = MAX(columns, 1);
+               colspace = width / columns;
+       }
+
        for (i = 0; g.gl_pathv[i]; i++) {
-               char *fname, *lname;
+               char *fname;
 
                fname = path_strip(g.gl_pathv[i], strip_path);
 
-               if (lflag) {
+               if (lflag & LONG_VIEW) {
+                       char *lname;
+                       struct stat sb;
+
                        /*
                         * XXX: this is slow - 1 roundtrip per path
                         * A solution to this is to fork glob() and
@@ -657,12 +726,19 @@ do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
                        printf("%s\n", lname);
                        xfree(lname);
                } else {
-                       /* XXX - multicolumn display would be nice here */
-                       printf("%s\n", fname);
+                       printf("%-*s", colspace, fname);
+                       if (c >= columns) {
+                               printf("\n");
+                               c = 1;
+                       } else
+                               c++;
                }
                xfree(fname);
        }
 
+       if (!(lflag & LONG_VIEW) && (c != 1))
+               printf("\n");
+
        if (g.gl_pathc)
                globfree(&g);
 
@@ -692,7 +768,7 @@ parse_args(const char **cpp, int *pflag, int *lflag, int *iflag,
                *iflag = 1;
                cp++;
        }
-               
+
        /* Figure out which command we have */
        for (i = 0; cmds[i].c; i++) {
                int cmdlen = strlen(cmds[i].c);
@@ -1082,6 +1158,7 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
 
                        err = parse_dispatch_command(conn, cmd, &pwd, 1);
                        xfree(dir);
+                       xfree(pwd);
                        return (err);
                }
                xfree(dir);
@@ -1105,14 +1182,16 @@ interactive_loop(int fd_in, int fd_out, char *file1, char *file2)
                if (fgets(cmd, sizeof(cmd), infile) == NULL) {
                        printf("\n");
                        break;
-               } else if (infile != stdin) /* Bluff typing */
+               }
+
+               if (batchmode) /* Echo command */
                        printf("%s", cmd);
 
                cp = strrchr(cmd, '\n');
                if (cp)
                        *cp = '\0';
 
-               err = parse_dispatch_command(conn, cmd, &pwd, infile != stdin);
+               err = parse_dispatch_command(conn, cmd, &pwd, batchmode);
                if (err != 0)
                        break;
        }
This page took 0.178857 seconds and 4 git commands to generate.