diff options
Diffstat (limited to 'sftp.c')
-rw-r--r-- | sftp.c | 58 |
1 files changed, 54 insertions, 4 deletions
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: sftp.c,v 1.178 2017/02/15 01:46:47 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,34 @@ 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 | #if defined(HAVE_STRUCT_STAT_ST_MTIM) | ||
899 | return (rmul * timespeccmp(&as->st_mtim, &bs->st_mtim, <)); | ||
900 | #elif defined(HAVE_STRUCT_STAT_ST_MTIME) | ||
901 | return (rmul * NCMP(as->st_mtime, bs->st_mtime)); | ||
902 | #else | ||
903 | return rmul * 1; | ||
904 | #endif | ||
905 | } else if (sort_flag & LS_SIZE_SORT) | ||
906 | return (rmul * NCMP(as->st_size, bs->st_size)); | ||
907 | |||
908 | fatal("Unknown ls sort type"); | ||
909 | } | ||
910 | |||
882 | /* sftp ls.1 replacement which handles path globs */ | 911 | /* sftp ls.1 replacement which handles path globs */ |
883 | static int | 912 | static int |
884 | do_globbed_ls(struct sftp_conn *conn, const char *path, | 913 | do_globbed_ls(struct sftp_conn *conn, const char *path, |
@@ -888,7 +917,8 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, | |||
888 | glob_t g; | 917 | glob_t g; |
889 | int err, r; | 918 | int err, r; |
890 | struct winsize ws; | 919 | struct winsize ws; |
891 | u_int i, c = 1, colspace = 0, columns = 1, m = 0, width = 80; | 920 | u_int i, j, nentries, *indices = NULL, c = 1; |
921 | u_int colspace = 0, columns = 1, m = 0, width = 80; | ||
892 | 922 | ||
893 | memset(&g, 0, sizeof(g)); | 923 | memset(&g, 0, sizeof(g)); |
894 | 924 | ||
@@ -933,7 +963,26 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, | |||
933 | colspace = width / columns; | 963 | colspace = width / columns; |
934 | } | 964 | } |
935 | 965 | ||
936 | for (i = 0; g.gl_pathv[i] && !interrupted; i++) { | 966 | /* |
967 | * Sorting: rather than mess with the contents of glob_t, prepare | ||
968 | * an array of indices into it and sort that. For the usual | ||
969 | * unsorted case, the indices are just the identity 1=1, 2=2, etc. | ||
970 | */ | ||
971 | for (nentries = 0; g.gl_pathv[nentries] != NULL; nentries++) | ||
972 | ; /* count entries */ | ||
973 | indices = calloc(nentries, sizeof(*indices)); | ||
974 | for (i = 0; i < nentries; i++) | ||
975 | indices[i] = i; | ||
976 | |||
977 | if (lflag & SORT_FLAGS) { | ||
978 | sort_glob = &g; | ||
979 | sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT); | ||
980 | qsort(indices, nentries, sizeof(*indices), sglob_comp); | ||
981 | sort_glob = NULL; | ||
982 | } | ||
983 | |||
984 | for (j = 0; j < nentries && !interrupted; j++) { | ||
985 | i = indices[j]; | ||
937 | fname = path_strip(g.gl_pathv[i], strip_path); | 986 | fname = path_strip(g.gl_pathv[i], strip_path); |
938 | if (lflag & LS_LONG_VIEW) { | 987 | if (lflag & LS_LONG_VIEW) { |
939 | if (g.gl_statv[i] == NULL) { | 988 | if (g.gl_statv[i] == NULL) { |
@@ -961,6 +1010,7 @@ do_globbed_ls(struct sftp_conn *conn, const char *path, | |||
961 | out: | 1010 | out: |
962 | if (g.gl_pathc) | 1011 | if (g.gl_pathc) |
963 | globfree(&g); | 1012 | globfree(&g); |
1013 | free(indices); | ||
964 | 1014 | ||
965 | return 0; | 1015 | return 0; |
966 | } | 1016 | } |
@@ -2246,7 +2296,7 @@ usage(void) | |||
2246 | extern char *__progname; | 2296 | extern char *__progname; |
2247 | 2297 | ||
2248 | fprintf(stderr, | 2298 | fprintf(stderr, |
2249 | "usage: %s [-1246aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" | 2299 | "usage: %s [-46aCfpqrv] [-B buffer_size] [-b batchfile] [-c cipher]\n" |
2250 | " [-D sftp_server_path] [-F ssh_config] " | 2300 | " [-D sftp_server_path] [-F ssh_config] " |
2251 | "[-i identity_file] [-l limit]\n" | 2301 | "[-i identity_file] [-l limit]\n" |
2252 | " [-o ssh_option] [-P port] [-R num_requests] " | 2302 | " [-o ssh_option] [-P port] [-R num_requests] " |