... and here is a patch to sftp(1) to make use of it.

Index: sftp.c
===================================================================
RCS file: /cvs/src/usr.bin/ssh/sftp.c,v
retrieving revision 1.126
diff -u -p -r1.126 sftp.c
--- sftp.c      22 Sep 2010 22:58:51 -0000      1.126
+++ sftp.c      23 Sep 2010 02:13:52 -0000
@@ -738,15 +738,18 @@ do_globbed_ls(struct sftp_conn *conn, ch
        glob_t g;
        u_int i, c = 1, colspace = 0, columns = 1;
        Attrib *a = NULL;
+       int err;
+       char *fname, *lname;
 
        memset(&g, 0, sizeof(g));
 
-       if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,
-           NULL, &g) || (g.gl_pathc && !g.gl_matchc)) {
+       if (remote_glob(conn, path,
+           GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE|GLOB_KEEPSTAT, NULL, &g) ||
+           (g.gl_pathc && !g.gl_matchc)) {
                if (g.gl_pathc)
                        globfree(&g);
                error("Can't ls: \"%s\" not found", path);
-               return (-1);
+               return -1;
        }
 
        if (interrupted)
@@ -756,19 +759,10 @@ do_globbed_ls(struct sftp_conn *conn, ch
         * If the glob returns a single match and it is a directory,
         * then just list its contents.
         */
-       if (g.gl_matchc == 1) {
-               if ((a = do_lstat(conn, g.gl_pathv[0], 1)) == NULL) {
-                       globfree(&g);
-                       return (-1);
-               }
-               if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
-                   S_ISDIR(a->perm)) {
-                       int err;
-
-                       err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
-                       globfree(&g);
-                       return (err);
-               }
+       if (g.gl_matchc == 1 && S_ISDIR(g.gl_statv[0].st_mode)) {
+               err = do_ls_dir(conn, g.gl_pathv[0], strip_path, lflag);
+               globfree(&g);
+               return err;
        }
 
        if (!(lflag & LS_SHORT_VIEW)) {
@@ -788,27 +782,10 @@ do_globbed_ls(struct sftp_conn *conn, ch
        }
 
        for (i = 0; g.gl_pathv[i] && !interrupted; i++, a = NULL) {
-               char *fname;
-
                fname = path_strip(g.gl_pathv[i], strip_path);
-
                if (lflag & LS_LONG_VIEW) {
-                       char *lname;
-                       struct stat sb;
-
-                       /*
-                        * 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));
-                       if (a == NULL)
-                               a = do_lstat(conn, g.gl_pathv[i], 1);
-                       if (a != NULL)
-                               attrib_to_stat(a, &sb);
-                       lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS));
+                       lname = ls_file(fname, &g.gl_statv[i], 1,
+                           (lflag & LS_SI_UNITS));
                        printf("%s\n", lname);
                        xfree(lname);
                } else {
@@ -829,7 +806,7 @@ do_globbed_ls(struct sftp_conn *conn, ch
        if (g.gl_pathc)
                globfree(&g);
 
-       return (0);
+       return 0;
 }
 
 static int

Reply via email to