... 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