From 72be5b2f8e7dc37235e8c4b8d0bc7b5ee1301505 Mon Sep 17 00:00:00 2001 From: "djm@openbsd.org" Date: Sat, 10 Jun 2017 06:33:34 +0000 Subject: upstream commit implement sorting for globbed ls; bz#2649 ok dtucker@ Upstream-ID: ed3110f351cc9703411bf847ba864041fb7216a8 --- sftp.c | 50 +++++++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 47 insertions(+), 3 deletions(-) (limited to 'sftp.c') diff --git a/sftp.c b/sftp.c index 9737bf50c..001c6ed2d 100644 --- a/sftp.c +++ b/sftp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: sftp.c,v 1.179 2017/05/02 08:54:19 djm Exp $ */ +/* $OpenBSD: sftp.c,v 1.180 2017/06/10 06:33:34 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller * @@ -106,6 +106,7 @@ volatile sig_atomic_t interrupted = 0; /* I wish qsort() took a separate ctx for the comparison function...*/ int sort_flag; +glob_t *sort_glob; /* Context used for commandline completion */ struct complete_ctx { @@ -879,6 +880,28 @@ do_ls_dir(struct sftp_conn *conn, const char *path, return (0); } +static int +sglob_comp(const void *aa, const void *bb) +{ + u_int a = *(const u_int *)aa; + u_int b = *(const u_int *)bb; + const char *ap = sort_glob->gl_pathv[a]; + const char *bp = sort_glob->gl_pathv[b]; + const struct stat *as = sort_glob->gl_statv[a]; + const struct stat *bs = sort_glob->gl_statv[b]; + int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; + +#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) + if (sort_flag & LS_NAME_SORT) + return (rmul * strcmp(ap, bp)); + else if (sort_flag & LS_TIME_SORT) + return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <)); + else if (sort_flag & LS_SIZE_SORT) + return (rmul * NCMP(as->st_size, bs->st_size)); + + fatal("Unknown ls sort type"); +} + /* sftp ls.1 replacement which handles path globs */ static int do_globbed_ls(struct sftp_conn *conn, const char *path, @@ -888,7 +911,8 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, glob_t g; int err, r; struct winsize ws; - u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; + u_int i, j, nentries, *indices = NULL, c = 1; + u_int colspace = 0, columns = 1, m = 0, width = 80; memset(&g, 0, sizeof(g)); @@ -933,7 +957,26 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, colspace = width / columns; } - for (i = 0; g.gl_pathv[i] && !interrupted; i++) { + /* + * Sorting: rather than mess with the contents of glob_t, prepare + * an array of indices into it and sort that. For the usual + * unsorted case, the indices are just the identity 1=1, 2=2, etc. + */ + for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++) + ; /* count entries */ + indices = calloc(nentries, sizeof(*indices)); + for (i = 0; i < nentries; i++) + indices[i] = i; + + if (lflag & SORT_FLAGS) { + sort_glob = &g; + sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); + qsort(indices, nentries, sizeof(*indices), sglob_comp); + sort_glob = NULL; + } + + for (j = 0; j < nentries && !interrupted; j++) { + i = indices[j]; fname = path_strip(g.gl_pathv[i], strip_path); if (lflag & LS_LONG_VIEW) { if (g.gl_statv[i] == NULL) { @@ -961,6 +1004,7 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, out: if (g.gl_pathc) globfree(&g); + free(indices); return 0; } -- cgit v1.2.3