diff options
author | djm@openbsd.org <djm@openbsd.org> | 2017-06-10 06:33:34 +0000 |
---|---|---|
committer | Damien Miller <djm@mindrot.org> | 2017-06-10 16:40:11 +1000 |
commit | 72be5b2f8e7dc37235e8c4b8d0bc7b5ee1301505 (patch) | |
tree | f4f4e131e174cbb5b8aabf68d0febb49ae432557 /sftp.c | |
parent | 5b2f34a74aa6a524cd57e856b23e1b7b25007721 (diff) |
upstream commit
implement sorting for globbed ls; bz#2649 ok dtucker@
Upstream-ID: ed3110f351cc9703411bf847ba864041fb7216a8
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 50 |
1 files changed, 47 insertions, 3 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.179 2017/05/02 08:54:19 djm Exp $ */ | 1 | /* $OpenBSD: sftp.c,v 1.180 2017/06/10 06:33:34 djm Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> | 3 | * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> |
4 | * | 4 | * |
@@ -106,6 +106,7 @@ volatile sig_atomic_t interrupted = 0; | |||
106 | 106 | ||
107 | /* I wish qsort() took a separate ctx for the comparison function...*/ | 107 | /* I wish qsort() took a separate ctx for the comparison function...*/ |
108 | int sort_flag; | 108 | int sort_flag; |
109 | glob_t *sort_glob; | ||
109 | 110 | ||
110 | /* Context used for commandline completion */ | 111 | /* Context used for commandline completion */ |
111 | struct complete_ctx { | 112 | struct complete_ctx { |
@@ -879,6 +880,28 @@ do_ls_dir(struct sftp_conn *conn, const char *path, | |||
879 | return (0); | 880 | return (0); |
880 | } | 881 | } |
881 | 882 | ||
883 | static int | ||
884 | sglob_comp(const void *aa, const void *bb) | ||
885 | { | ||
886 | u_int a = *(const u_int *)aa; | ||
887 | u_int b = *(const u_int *)bb; | ||
888 | const char *ap = sort_glob->gl_pathv[a]; | ||
889 | const char *bp = sort_glob->gl_pathv[b]; | ||
890 | const struct stat *as = sort_glob->gl_statv[a]; | ||
891 | const struct stat *bs = sort_glob->gl_statv[b]; | ||
892 | int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1; | ||
893 | |||
894 | #define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1)) | ||
895 | if (sort_flag & LS_NAME_SORT) | ||
896 | return (rmul * strcmp(ap, bp)); | ||
897 | else if (sort_flag & LS_TIME_SORT) | ||
898 | return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <)); | ||
899 | else if (sort_flag & LS_SIZE_SORT) | ||
900 | return (rmul * NCMP(as->st_size, bs->st_size)); | ||
901 | |||
902 | fatal("Unknown ls sort type"); | ||
903 | } | ||
904 | |||
882 | /* sftp ls.1 replacement which handles path globs */ | 905 | /* sftp ls.1 replacement which handles path globs */ |
883 | static int | 906 | static int |
884 | do_globbed_ls(struct sftp_conn *conn, const char *path, | 907 | do_globbed_ls(struct sftp_conn *conn, const char *path, |
@@ -888,7 +911,8 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, | |||
888 | glob_t g; | 911 | glob_t g; |
889 | int err, r; | 912 | int err, r; |
890 | struct winsize ws; | 913 | struct winsize ws; |
891 | u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; | 914 | u_int i, j, nentries, *indices = NULL, c = 1; |
915 | u_int colspace = 0, columns = 1, m = 0, width = 80; | ||
892 | 916 | ||
893 | memset(&g, 0, sizeof(g)); | 917 | memset(&g, 0, sizeof(g)); |
894 | 918 | ||
@@ -933,7 +957,26 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, | |||
933 | colspace = width / columns; | 957 | colspace = width / columns; |
934 | } | 958 | } |
935 | 959 | ||
936 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 960 | /* |
961 | * Sorting: rather than mess with the contents of glob_t, prepare | ||
962 | * an array of indices into it and sort that. For the usual | ||
963 | * unsorted case, the indices are just the identity 1=1, 2=2, etc. | ||
964 | */ | ||
965 | for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++) | ||
966 | ; /* count entries */ | ||
967 | indices = calloc(nentries, sizeof(*indices)); | ||
968 | for (i = 0; i < nentries; i++) | ||
969 | indices[i] = i; | ||
970 | |||
971 | if (lflag & SORT_FLAGS) { | ||
972 | sort_glob = &g; | ||
973 | sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); | ||
974 | qsort(indices, nentries, sizeof(*indices), sglob_comp); | ||
975 | sort_glob = NULL; | ||
976 | } | ||
977 | |||
978 | for (j = 0; j < nentries && !interrupted; j++) { | ||
979 | i = indices[j]; | ||
937 | fname = path_strip(g.gl_pathv[i], strip_path); | 980 | fname = path_strip(g.gl_pathv[i], strip_path); |
938 | if (lflag & LS_LONG_VIEW) { | 981 | if (lflag & LS_LONG_VIEW) { |
939 | if (g.gl_statv[i] == NULL) { | 982 | if (g.gl_statv[i] == NULL) { |
@@ -961,6 +1004,7 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, | |||
961 | out: | 1004 | out: |
962 | if (g.gl_pathc) | 1005 | if (g.gl_pathc) |
963 | globfree(&g); | 1006 | globfree(&g); |
1007 | free(indices); | ||
964 | 1008 | ||
965 | return 0; | 1009 | return 0; |
966 | } | 1010 | } |