- djm@cvs.openbsd.org 2010/01/13 01:40:16
     [sftp.c sftp-server.c sftp.1 sftp-common.c sftp-common.h]
     support '-h' (human-readable units) for sftp's ls command, just like
     ls(1); ok dtucker@
diff --git a/ChangeLog b/ChangeLog
index 7624812..d421035 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -18,6 +18,10 @@
      [canohost.c ssh-keysign.c sshconnect2.c]
      Make HostBased authentication work with a ProxyCommand.  bz #1569, patch
      from imorgan at nas nasa gov, ok djm@
+   - djm@cvs.openbsd.org 2010/01/13 01:40:16
+     [sftp.c sftp-server.c sftp.1 sftp-common.c sftp-common.h]
+     support '-h' (human-readable units) for sftp's ls command, just like
+     ls(1); ok dtucker@
 
 20100112
  - (dtucker) OpenBSD CVS Sync
diff --git a/sftp-common.c b/sftp-common.c
index 7ebadcc..7393fc6 100644
--- a/sftp-common.c
+++ b/sftp-common.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-common.c,v 1.20 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: sftp-common.c,v 1.21 2010/01/13 01:40:16 djm Exp $ */
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
  * Copyright (c) 2001 Damien Miller.  All rights reserved.
@@ -36,6 +36,7 @@
 #include <string.h>
 #include <time.h>
 #include <stdarg.h>
+#include <util.h>
 
 #include "xmalloc.h"
 #include "buffer.h"
@@ -184,7 +185,7 @@
  * drwxr-xr-x    5 markus   markus       1024 Jan 13 18:39 .ssh
  */
 char *
-ls_file(const char *name, const struct stat *st, int remote)
+ls_file(const char *name, const struct stat *st, int remote, int si_units)
 {
 	int ulen, glen, sz = 0;
 	struct passwd *pw;
@@ -192,6 +193,7 @@
 	struct tm *ltime = localtime(&st->st_mtime);
 	char *user, *group;
 	char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
+	char sbuf[FMT_SCALED_STRSIZE];
 
 	strmode(st->st_mode, mode);
 	if (!remote && (pw = getpwuid(st->st_uid)) != NULL) {
@@ -216,8 +218,15 @@
 		tbuf[0] = '\0';
 	ulen = MAX(strlen(user), 8);
 	glen = MAX(strlen(group), 8);
-	snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode,
-	    (u_int)st->st_nlink, ulen, user, glen, group,
-	    (unsigned long long)st->st_size, tbuf, name);
+	if (si_units) {
+		fmt_scaled((long long)st->st_size, sbuf);
+		snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8s %s %s", mode,
+		    (u_int)st->st_nlink, ulen, user, glen, group,
+		    sbuf, tbuf, name);
+	} else {
+		snprintf(buf, sizeof buf, "%s %3u %-*s %-*s %8llu %s %s", mode,
+		    (u_int)st->st_nlink, ulen, user, glen, group,
+		    (unsigned long long)st->st_size, tbuf, name);
+	}
 	return xstrdup(buf);
 }
diff --git a/sftp-common.h b/sftp-common.h
index 9b58484..9ed86c0 100644
--- a/sftp-common.h
+++ b/sftp-common.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-common.h,v 1.10 2006/08/03 03:34:42 deraadt Exp $ */
+/* $OpenBSD: sftp-common.h,v 1.11 2010/01/13 01:40:16 djm Exp $ */
 
 /*
  * Copyright (c) 2001 Markus Friedl.  All rights reserved.
@@ -46,6 +46,6 @@
 void	 attrib_to_stat(const Attrib *, struct stat *);
 Attrib	*decode_attrib(Buffer *);
 void	 encode_attrib(Buffer *, const Attrib *);
-char	*ls_file(const char *, const struct stat *, int);
+char	*ls_file(const char *, const struct stat *, int, int);
 
 const char *fx2txt(int);
diff --git a/sftp-server.c b/sftp-server.c
index ab9391c..a98ac2b 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp-server.c,v 1.90 2010/01/09 00:20:26 djm Exp $ */
+/* $OpenBSD: sftp-server.c,v 1.91 2010/01/13 01:40:16 djm Exp $ */
 /*
  * Copyright (c) 2000-2004 Markus Friedl.  All rights reserved.
  *
@@ -940,7 +940,7 @@
 				continue;
 			stat_to_attrib(&st, &(stats[count].attrib));
 			stats[count].name = xstrdup(dp->d_name);
-			stats[count].long_name = ls_file(dp->d_name, &st, 0);
+			stats[count].long_name = ls_file(dp->d_name, &st, 0, 0);
 			count++;
 			/* send up to 100 entries in one message */
 			/* XXX check packet size instead */
diff --git a/sftp.1 b/sftp.1
index 3ec7a02..f6371cf 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: sftp.1,v 1.80 2010/01/09 23:04:13 dtucker Exp $
+.\" $OpenBSD: sftp.1,v 1.81 2010/01/13 01:40:16 djm Exp $
 .\"
 .\" Copyright (c) 2001 Damien Miller.  All rights reserved.
 .\"
@@ -22,7 +22,7 @@
 .\" (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 .\" THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 .\"
-.Dd $Mdocdate: January 9 2010 $
+.Dd $Mdocdate: January 13 2010 $
 .Dt SFTP 1
 .Os
 .Sh NAME
@@ -393,7 +393,7 @@
 .It Ic lpwd
 Print local working directory.
 .It Xo Ic ls
-.Op Fl 1aflnrSt
+.Op Fl 1aflhnrSt
 .Op Ar path
 .Xc
 Display a remote directory listing of either
@@ -421,6 +421,11 @@
 .It Fl l
 Display additional details including permissions
 and ownership information.
+.It Fl h
+When used with a long format option, use unit suffixes: Byte, Kilobyte,
+Megabyte, Gigabyte, Terabyte, Petabyte, and Exabyte in order to reduce
+the number of digits to four or fewer using powers of 2 for sizes (K=1024,
+M=1048576, etc.).
 .It Fl n
 Produce a long listing with user and group information presented
 numerically.
diff --git a/sftp.c b/sftp.c
index 78f8ca1..16f8498 100644
--- a/sftp.c
+++ b/sftp.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sftp.c,v 1.118 2010/01/09 11:13:02 dtucker Exp $ */
+/* $OpenBSD: sftp.c,v 1.119 2010/01/13 01:40:16 djm Exp $ */
 /*
  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
  *
@@ -110,16 +110,17 @@
 #define WHITESPACE " \t\r\n"
 
 /* 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 LS_LONG_VIEW	0x0001	/* Full view ala ls -l */
+#define LS_SHORT_VIEW	0x0002	/* Single row view ala ls -1 */
+#define LS_NUMERIC_VIEW	0x0004	/* Long view with numeric uid/gid */
+#define LS_NAME_SORT	0x0008	/* Sort by name (default) */
+#define LS_TIME_SORT	0x0010	/* Sort by mtime */
+#define LS_SIZE_SORT	0x0020	/* Sort by file size */
+#define LS_REVERSE_SORT	0x0040	/* Reverse sort order */
+#define LS_SHOW_ALL	0x0080	/* Don't skip filenames starting with '.' */
+#define LS_SI_UNITS	0x0100	/* Display sizes as K, M, G, etc. */
 
-#define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW)
+#define VIEW_FLAGS	(LS_LONG_VIEW|LS_SHORT_VIEW|LS_NUMERIC_VIEW|LS_SI_UNITS)
 #define SORT_FLAGS	(LS_NAME_SORT|LS_TIME_SORT|LS_SIZE_SORT)
 
 /* Commands for interactive mode */
@@ -383,7 +384,7 @@
 	opterr = 0;
 
 	*lflag = LS_NAME_SORT;
-	while ((ch = getopt(argc, argv, "1Saflnrt")) != -1) {
+	while ((ch = getopt(argc, argv, "1Safhlnrt")) != -1) {
 		switch (ch) {
 		case '1':
 			*lflag &= ~VIEW_FLAGS;
@@ -399,12 +400,15 @@
 		case 'f':
 			*lflag &= ~SORT_FLAGS;
 			break;
+		case 'h':
+			*lflag |= LS_SI_UNITS;
+			break;
 		case 'l':
-			*lflag &= ~VIEW_FLAGS;
+			*lflag &= ~LS_SHORT_VIEW;
 			*lflag |= LS_LONG_VIEW;
 			break;
 		case 'n':
-			*lflag &= ~VIEW_FLAGS;
+			*lflag &= ~LS_SHORT_VIEW;
 			*lflag |= LS_NUMERIC_VIEW|LS_LONG_VIEW;
 			break;
 		case 'r':
@@ -716,13 +720,14 @@
 		xfree(tmp);
 
 		if (lflag & LS_LONG_VIEW) {
-			if (lflag & LS_NUMERIC_VIEW) {
+			if (lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) {
 				char *lname;
 				struct stat sb;
 
 				memset(&sb, 0, sizeof(sb));
 				attrib_to_stat(&d[n]->a, &sb);
-				lname = ls_file(fname, &sb, 1);
+				lname = ls_file(fname, &sb, 1,
+				    (lflag & LS_SI_UNITS));
 				printf("%s\n", lname);
 				xfree(lname);
 			} else
@@ -824,7 +829,7 @@
 				a = do_lstat(conn, g.gl_pathv[i], 1);
 			if (a != NULL)
 				attrib_to_stat(a, &sb);
-			lname = ls_file(fname, &sb, 1);
+			lname = ls_file(fname, &sb, 1, (lflag & LS_SI_UNITS));
 			printf("%s\n", lname);
 			xfree(lname);
 		} else {