#include "includes.h"
-RCSID("$OpenBSD: sftp.c,v 1.50 2004/06/20 18:53:39 djm Exp $");
+RCSID("$OpenBSD: sftp.c,v 1.56 2004/07/11 17:48:47 deraadt Exp $");
#include "buffer.h"
#include "xmalloc.h"
/* SIGINT received during command processing */
volatile sig_atomic_t interrupted = 0;
+/* I wish qsort() took a separate ctx for the comparison function...*/
+int sort_flag;
+
int remote_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *); /* proto for sftp-glob.c */
-#ifdef HAVE___PROGNAME
extern char *__progname;
-#else
-char *__progname;
-#endif
/* Separators for interactive commands */
#define WHITESPACE " \t\r\n"
-/* Define what type of ls view */
-#define LONG_VIEW 1 /* Full view ala ls -l */
-#define SHORT_VIEW 2 /* Single row view ala ls -1 */
-#define NUMERIC_VIEW 4 /* Long view with numeric uid/gid */
-#define VIEW_FLAGS (LONG_VIEW|SHORT_VIEW|NUMERIC_VIEW)
+/* ls flags */
+#define LS_LONG_VIEW 0x01 /* Full view ala ls -l */
+#define LS_SHORT_VIEW 0x02 /* Single row view ala ls -1 */
+#define LS_NUMERIC_VIEW 0x04 /* Long view with numeric uid/gid */
+#define LS_NAME_SORT 0x08 /* Sort by name (default) */
+#define LS_TIME_SORT 0x10 /* Sort by mtime */
+#define LS_SIZE_SORT 0x20 /* Sort by file size */
+#define LS_REVERSE_SORT 0x40 /* Reverse sort order */
+#define LS_SHOW_ALL 0x80 /* Don't skip filenames starting with '.' */
+
+#define VIEW_FLAGS (LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW)
+#define SORT_FLAGS (LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
/* Commands for interactive mode */
#define I_CHDIR 1
static char *
make_absolute(char *p, char *pwd)
{
- char *abs;
+ char *abs_str;
/* Derelativise */
if (p && p[0] != '/') {
- abs = path_append(pwd, p);
+ abs_str = path_append(pwd, p);
xfree(p);
- return(abs);
+ return(abs_str);
} else
return(p);
}
{
const char *cp = *cpp;
+ /* Defaults */
+ *lflag = LS_NAME_SORT;
+
/* Check for flags */
if (cp++[0] == '-') {
for(; strchr(WHITESPACE, *cp) == NULL; cp++) {
switch (*cp) {
case 'l':
*lflag &= ~VIEW_FLAGS;
- *lflag |= LONG_VIEW;
+ *lflag |= LS_LONG_VIEW;
break;
case '1':
*lflag &= ~VIEW_FLAGS;
- *lflag |= SHORT_VIEW;
+ *lflag |= LS_SHORT_VIEW;
break;
case 'n':
*lflag &= ~VIEW_FLAGS;
- *lflag |= NUMERIC_VIEW|LONG_VIEW;
+ *lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
+ break;
+ case 'S':
+ *lflag &= ~SORT_FLAGS;
+ *lflag |= LS_SIZE_SORT;
+ break;
+ case 't':
+ *lflag &= ~SORT_FLAGS;
+ *lflag |= LS_TIME_SORT;
+ break;
+ case 'r':
+ *lflag |= LS_REVERSE_SORT;
+ break;
+ case 'f':
+ *lflag &= ~SORT_FLAGS;
+ break;
+ case 'a':
+ *lflag |= LS_SHOW_ALL;
break;
default:
error("Invalid flag -%c", *cp);
i++;
if (cp[i] != '\'' && cp[i] != '\"' &&
cp[i] != '\\') {
- error("Bad escaped character '\%c'",
+ error("Bad escaped character '\\%c'",
cp[i]);
goto fail;
}
{
SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
+ int rmul = sort_flag & LS_REVERSE_SORT ? -1 : 1;
- return (strcmp(a->filename, b->filename));
+#define NCMP(a,b) (a == b ? 0 : (a < b ? 1 : -1))
+ if (sort_flag & LS_NAME_SORT)
+ return (rmul * strcmp(a->filename, b->filename));
+ else if (sort_flag & LS_TIME_SORT)
+ return (rmul * NCMP(a->a.mtime, b->a.mtime));
+ else if (sort_flag & LS_SIZE_SORT)
+ return (rmul * NCMP(a->a.size, b->a.size));
+
+ fatal("Unknown ls sort type");
}
/* sftp ls.1 replacement for directories */
if ((n = do_readdir(conn, path, &d)) != 0)
return (n);
- if (!(lflag & SHORT_VIEW)) {
+ if (!(lflag & LS_SHORT_VIEW)) {
int m = 0, width = 80;
struct winsize ws;
char *tmp;
/* Count entries for sort and find longest filename */
- for (n = 0; d[n] != NULL; n++)
- m = MAX(m, strlen(d[n]->filename));
+ for (n = 0; d[n] != NULL; n++) {
+ if (d[n]->filename[0] != '.' || (lflag & LS_SHOW_ALL))
+ m = MAX(m, strlen(d[n]->filename));
+ }
/* Add any subpath that also needs to be counted */
tmp = path_strip(path, strip_path);
colspace = MIN(colspace, width);
}
- qsort(d, n, sizeof(*d), sdirent_comp);
+ if (lflag & SORT_FLAGS) {
+ sort_flag = lflag & (SORT_FLAGS|LS_REVERSE_SORT);
+ qsort(d, n, sizeof(*d), sdirent_comp);
+ }
for (n = 0; d[n] != NULL && !interrupted; n++) {
char *tmp, *fname;
+ if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
+ continue;
+
tmp = path_append(path, d[n]->filename);
fname = path_strip(tmp, strip_path);
xfree(tmp);
- if (lflag & LONG_VIEW) {
- if (lflag & NUMERIC_VIEW) {
+ if (lflag & LS_LONG_VIEW) {
+ if (lflag & LS_NUMERIC_VIEW) {
char *lname;
struct stat sb;
xfree(fname);
}
- if (!(lflag & LONG_VIEW) && (c != 1))
+ if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n");
free_sftp_dirents(d);
}
}
- if (!(lflag & SHORT_VIEW)) {
+ if (!(lflag & LS_SHORT_VIEW)) {
int m = 0, width = 80;
struct winsize ws;
fname = path_strip(g.gl_pathv[i], strip_path);
- if (lflag & LONG_VIEW) {
+ if (lflag & LS_LONG_VIEW) {
char *lname;
struct stat sb;
xfree(fname);
}
- if (!(lflag & LONG_VIEW) && (c != 1))
+ if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n");
out:
/*
* The underlying ssh is in the same process group, so we must
- * ignore SIGINT if we want to gracefully abort commands,
- * otherwise the signal will make it to the ssh process and
+ * ignore SIGINT if we want to gracefully abort commands,
+ * otherwise the signal will make it to the ssh process and
* kill it too
*/
signal(SIGINT, SIG_IGN);
fatal("Batch file already specified.");
/* Allow "-" as stdin */
- if (strcmp(optarg, "-") != 0 &&
+ if (strcmp(optarg, "-") != 0 &&
(infile = fopen(optarg, "r")) == NULL)
fatal("%s (%s).", strerror(errno), optarg);
showprogress = 0;