summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog6
-rw-r--r--sftp-client.c8
-rw-r--r--sftp-client.h5
-rw-r--r--sftp-common.c64
-rw-r--r--sftp-common.h4
-rw-r--r--sftp-glob.c21
-rw-r--r--sftp-glob.h5
-rw-r--r--sftp-int.c204
-rw-r--r--sftp-server.c46
-rw-r--r--sftp.112
10 files changed, 270 insertions, 105 deletions
diff --git a/ChangeLog b/ChangeLog
index 055b18b6b..7b0053d25 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -22,6 +22,10 @@
22 [authfd.c authfd.h ssh.c] 22 [authfd.c authfd.h ssh.c]
23 don't connect to agent to test for presence if we've previously 23 don't connect to agent to test for presence if we've previously
24 connected; ok markus@ 24 connected; ok markus@
25 - djm@cvs.openbsd.org 2002/09/11 22:41:50
26 [sftp.1 sftp-client.c sftp-client.h sftp-common.c sftp-common.h]
27 [sftp-glob.c sftp-glob.h sftp-int.c sftp-server.c]
28 support for short/long listings and globbing in "ls"; ok markus@
25 29
2620020911 3020020911
27 - (djm) Sync openbsd-compat with OpenBSD -current 31 - (djm) Sync openbsd-compat with OpenBSD -current
@@ -1642,4 +1646,4 @@
1642 - (stevesk) entropy.c: typo in debug message 1646 - (stevesk) entropy.c: typo in debug message
1643 - (djm) ssh-keygen -i needs seeded RNG; report from markus@ 1647 - (djm) ssh-keygen -i needs seeded RNG; report from markus@
1644 1648
1645$Id: ChangeLog,v 1.2457 2002/09/11 23:52:46 djm Exp $ 1649$Id: ChangeLog,v 1.2458 2002/09/11 23:54:25 djm Exp $
diff --git a/sftp-client.c b/sftp-client.c
index c797482a8..f77596813 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -28,7 +28,7 @@
28/* XXX: copy between two remote sites */ 28/* XXX: copy between two remote sites */
29 29
30#include "includes.h" 30#include "includes.h"
31RCSID("$OpenBSD: sftp-client.c,v 1.34 2002/06/27 10:35:47 deraadt Exp $"); 31RCSID("$OpenBSD: sftp-client.c,v 1.35 2002/09/11 22:41:49 djm Exp $");
32 32
33#include "openbsd-compat/fake-queue.h" 33#include "openbsd-compat/fake-queue.h"
34 34
@@ -415,12 +415,6 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
415} 415}
416 416
417int 417int
418do_ls(struct sftp_conn *conn, char *path)
419{
420 return(do_lsreaddir(conn, path, 1, NULL));
421}
422
423int
424do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 418do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
425{ 419{
426 return(do_lsreaddir(conn, path, 0, dir)); 420 return(do_lsreaddir(conn, path, 0, dir));
diff --git a/sftp-client.h b/sftp-client.h
index b06171168..98e08ffa7 100644
--- a/sftp-client.h
+++ b/sftp-client.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-client.h,v 1.10 2002/06/23 09:30:14 deraadt Exp $ */ 1/* $OpenBSD: sftp-client.h,v 1.11 2002/09/11 22:41:50 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 4 * Copyright (c) 2001,2002 Damien Miller. All rights reserved.
@@ -48,9 +48,6 @@ u_int sftp_proto_version(struct sftp_conn *);
48/* Close file referred to by 'handle' */ 48/* Close file referred to by 'handle' */
49int do_close(struct sftp_conn *, char *, u_int); 49int do_close(struct sftp_conn *, char *, u_int);
50 50
51/* List contents of directory 'path' to stdout */
52int do_ls(struct sftp_conn *, char *);
53
54/* Read contents of 'path' to NULL-terminated array 'dir' */ 51/* Read contents of 'path' to NULL-terminated array 'dir' */
55int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***); 52int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***);
56 53
diff --git a/sftp-common.c b/sftp-common.c
index 6bed0ab8a..082345486 100644
--- a/sftp-common.c
+++ b/sftp-common.c
@@ -24,7 +24,7 @@
24 */ 24 */
25 25
26#include "includes.h" 26#include "includes.h"
27RCSID("$OpenBSD: sftp-common.c,v 1.6 2002/06/23 09:30:14 deraadt Exp $"); 27RCSID("$OpenBSD: sftp-common.c,v 1.7 2002/09/11 22:41:50 djm Exp $");
28 28
29#include "buffer.h" 29#include "buffer.h"
30#include "bufaux.h" 30#include "bufaux.h"
@@ -65,6 +65,26 @@ stat_to_attrib(struct stat *st, Attrib *a)
65 a->mtime = st->st_mtime; 65 a->mtime = st->st_mtime;
66} 66}
67 67
68/* Convert from filexfer attribs to struct stat */
69void
70attrib_to_stat(Attrib *a, struct stat *st)
71{
72 memset(st, 0, sizeof(*st));
73
74 if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
75 st->st_size = a->size;
76 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
77 st->st_uid = a->uid;
78 st->st_gid = a->gid;
79 }
80 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
81 st->st_mode = a->perm;
82 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
83 st->st_atime = a->atime;
84 st->st_mtime = a->mtime;
85 }
86}
87
68/* Decode attributes in buffer */ 88/* Decode attributes in buffer */
69Attrib * 89Attrib *
70decode_attrib(Buffer *b) 90decode_attrib(Buffer *b)
@@ -149,3 +169,45 @@ fx2txt(int status)
149 } 169 }
150 /* NOTREACHED */ 170 /* NOTREACHED */
151} 171}
172
173/*
174 * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
175 */
176char *
177ls_file(char *name, struct stat *st, int remote)
178{
179 int ulen, glen, sz = 0;
180 struct passwd *pw;
181 struct group *gr;
182 struct tm *ltime = localtime(&st->st_mtime);
183 char *user, *group;
184 char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
185
186 strmode(st->st_mode, mode);
187 if (!remote && (pw = getpwuid(st->st_uid)) != NULL) {
188 user = pw->pw_name;
189 } else {
190 snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
191 user = ubuf;
192 }
193 if (!remote && (gr = getgrgid(st->st_gid)) != NULL) {
194 group = gr->gr_name;
195 } else {
196 snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
197 group = gbuf;
198 }
199 if (ltime != NULL) {
200 if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
201 sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
202 else
203 sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
204 }
205 if (sz == 0)
206 tbuf[0] = '\0';
207 ulen = MAX(strlen(user), 8);
208 glen = MAX(strlen(group), 8);
209 snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode,
210 st->st_nlink, ulen, user, glen, group,
211 (u_int64_t)st->st_size, tbuf, name);
212 return xstrdup(buf);
213}
diff --git a/sftp-common.h b/sftp-common.h
index 4c126bf10..201611cc4 100644
--- a/sftp-common.h
+++ b/sftp-common.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-common.h,v 1.3 2001/06/26 17:27:24 markus Exp $ */ 1/* $OpenBSD: sftp-common.h,v 1.4 2002/09/11 22:41:50 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001 Markus Friedl. All rights reserved. 4 * Copyright (c) 2001 Markus Friedl. All rights reserved.
@@ -40,7 +40,9 @@ struct Attrib {
40 40
41void attrib_clear(Attrib *); 41void attrib_clear(Attrib *);
42void stat_to_attrib(struct stat *, Attrib *); 42void stat_to_attrib(struct stat *, Attrib *);
43void attrib_to_stat(Attrib *, struct stat *);
43Attrib *decode_attrib(Buffer *); 44Attrib *decode_attrib(Buffer *);
44void encode_attrib(Buffer *, Attrib *); 45void encode_attrib(Buffer *, Attrib *);
46char *ls_file(char *, struct stat *, int);
45 47
46const char *fx2txt(int); 48const char *fx2txt(int);
diff --git a/sftp-glob.c b/sftp-glob.c
index 2a7cf141c..ee122a2cd 100644
--- a/sftp-glob.c
+++ b/sftp-glob.c
@@ -23,7 +23,7 @@
23 */ 23 */
24 24
25#include "includes.h" 25#include "includes.h"
26RCSID("$OpenBSD: sftp-glob.c,v 1.12 2002/07/04 04:15:33 deraadt Exp $"); 26RCSID("$OpenBSD: sftp-glob.c,v 1.13 2002/09/11 22:41:50 djm Exp $");
27 27
28#include "buffer.h" 28#include "buffer.h"
29#include "bufaux.h" 29#include "bufaux.h"
@@ -107,25 +107,6 @@ fudge_closedir(struct SFTP_OPENDIR *od)
107 xfree(od); 107 xfree(od);
108} 108}
109 109
110static void
111attrib_to_stat(Attrib *a, struct stat *st)
112{
113 memset(st, 0, sizeof(*st));
114
115 if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
116 st->st_size = a->size;
117 if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
118 st->st_uid = a->uid;
119 st->st_gid = a->gid;
120 }
121 if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
122 st->st_mode = a->perm;
123 if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
124 st->st_atime = a->atime;
125 st->st_mtime = a->mtime;
126 }
127}
128
129static int 110static int
130fudge_lstat(const char *path, struct stat *st) 111fudge_lstat(const char *path, struct stat *st)
131{ 112{
diff --git a/sftp-glob.h b/sftp-glob.h
index 9c754912c..f879e8719 100644
--- a/sftp-glob.h
+++ b/sftp-glob.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: sftp-glob.h,v 1.7 2002/03/19 10:49:35 markus Exp $ */ 1/* $OpenBSD: sftp-glob.h,v 1.8 2002/09/11 22:41:50 djm Exp $ */
2 2
3/* 3/*
4 * Copyright (c) 2001,2002 Damien Miller. All rights reserved. 4 * Copyright (c) 2001,2002 Damien Miller. All rights reserved.
@@ -31,8 +31,7 @@
31 31
32#include "sftp-client.h" 32#include "sftp-client.h"
33 33
34int 34int remote_glob(struct sftp_conn *, const char *, int,
35remote_glob(struct sftp_conn *, const char *, int,
36 int (*)(const char *, int), glob_t *); 35 int (*)(const char *, int), glob_t *);
37 36
38#endif 37#endif
diff --git a/sftp-int.c b/sftp-int.c
index b13e5da5d..d3dc085e2 100644
--- a/sftp-int.c
+++ b/sftp-int.c
@@ -22,11 +22,10 @@
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */ 23 */
24 24
25/* XXX: globbed ls */
26/* XXX: recursive operations */ 25/* XXX: recursive operations */
27 26
28#include "includes.h" 27#include "includes.h"
29RCSID("$OpenBSD: sftp-int.c,v 1.47 2002/06/23 09:30:14 deraadt Exp $"); 28RCSID("$OpenBSD: sftp-int.c,v 1.48 2002/09/11 22:41:50 djm Exp $");
30 29
31#include "buffer.h" 30#include "buffer.h"
32#include "xmalloc.h" 31#include "xmalloc.h"
@@ -201,6 +200,26 @@ local_do_ls(const char *args)
201 } 200 }
202} 201}
203 202
203/* Strip one path (usually the pwd) from the start of another */
204static char *
205path_strip(char *path, char *strip)
206{
207 size_t len;
208 char *ret;
209
210 if (strip == NULL)
211 return (xstrdup(path));
212
213 len = strlen(strip);
214 if (strip != NULL && strncmp(path, strip, len) == 0) {
215 if (strip[len - 1] != '/' && path[len] == '/')
216 len++;
217 return (xstrdup(path + len));
218 }
219
220 return (xstrdup(path));
221}
222
204static char * 223static char *
205path_append(char *p1, char *p2) 224path_append(char *p1, char *p2)
206{ 225{
@@ -209,7 +228,7 @@ path_append(char *p1, char *p2)
209 228
210 ret = xmalloc(len); 229 ret = xmalloc(len);
211 strlcpy(ret, p1, len); 230 strlcpy(ret, p1, len);
212 if (strcmp(p1, "/") != 0) 231 if (p1[strlen(p1) - 1] != '/')
213 strlcat(ret, "/", len); 232 strlcat(ret, "/", len);
214 strlcat(ret, p2, len); 233 strlcat(ret, p2, len);
215 234
@@ -274,6 +293,29 @@ parse_getput_flags(const char **cpp, int *pflag)
274} 293}
275 294
276static int 295static int
296parse_ls_flags(const char **cpp, int *lflag)
297{
298 const char *cp = *cpp;
299
300 /* Check for flags */
301 if (cp++[0] == '-') {
302 for(; strchr(WHITESPACE, *cp) == NULL; cp++) {
303 switch (*cp) {
304 case 'l':
305 *lflag = 1;
306 break;
307 default:
308 error("Invalid flag -%c", *cp);
309 return(-1);
310 }
311 }
312 *cpp = cp + strspn(cp, WHITESPACE);
313 }
314
315 return(0);
316}
317
318static int
277get_pathname(const char **cpp, char **path) 319get_pathname(const char **cpp, char **path)
278{ 320{
279 const char *cp = *cpp, *end; 321 const char *cp = *cpp, *end;
@@ -504,8 +546,129 @@ out:
504} 546}
505 547
506static int 548static int
507parse_args(const char **cpp, int *pflag, unsigned long *n_arg, 549sdirent_comp(const void *aa, const void *bb)
508 char **path1, char **path2) 550{
551 SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
552 SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
553
554 return (strcmp(a->filename, b->filename));
555}
556
557/* sftp ls.1 replacement for directories */
558static int
559do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
560{
561 int n;
562 SFTP_DIRENT **d;
563
564 if ((n = do_readdir(conn, path, &d)) != 0)
565 return (n);
566
567 /* Count entries for sort */
568 for (n = 0; d[n] != NULL; n++)
569 ;
570
571 qsort(d, n, sizeof(*d), sdirent_comp);
572
573 for (n = 0; d[n] != NULL; n++) {
574 char *tmp, *fname;
575
576 tmp = path_append(path, d[n]->filename);
577 fname = path_strip(tmp, strip_path);
578 xfree(tmp);
579
580 if (lflag) {
581 char *lname;
582 struct stat sb;
583
584 memset(&sb, 0, sizeof(sb));
585 attrib_to_stat(&d[n]->a, &sb);
586 lname = ls_file(fname, &sb, 1);
587 printf("%s\n", lname);
588 xfree(lname);
589 } else {
590 /* XXX - multicolumn display would be nice here */
591 printf("%s\n", fname);
592 }
593
594 xfree(fname);
595 }
596
597 free_sftp_dirents(d);
598 return (0);
599}
600
601/* sftp ls.1 replacement which handles path globs */
602static int
603do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
604 int lflag)
605{
606 glob_t g;
607 int i;
608 Attrib *a;
609 struct stat sb;
610
611 memset(&g, 0, sizeof(g));
612
613 if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,
614 NULL, &g)) {
615 error("Can't ls: \"%s\" not found", path);
616 return (-1);
617 }
618
619 /*
620 * If the glob returns a single match, which is the same as the
621 * input glob, and it is a directory, then just list its contents
622 */
623 if (g.gl_pathc == 1 &&
624 strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) {
625 if ((a = do_lstat(conn, path, 1)) == NULL) {
626 globfree(&g);
627 return (-1);
628 }
629 if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
630 S_ISDIR(a->perm)) {
631 globfree(&g);
632 return (do_ls_dir(conn, path, strip_path, lflag));
633 }
634 }
635
636 for (i = 0; g.gl_pathv[i]; i++) {
637 char *fname, *lname;
638
639 fname = path_strip(g.gl_pathv[i], strip_path);
640
641 if (lflag) {
642 /*
643 * XXX: this is slow - 1 roundtrip per path
644 * A solution to this is to fork glob() and
645 * build a sftp specific version which keeps the
646 * attribs (which currently get thrown away)
647 * that the server returns as well as the filenames.
648 */
649 memset(&sb, 0, sizeof(sb));
650 a = do_lstat(conn, g.gl_pathv[i], 1);
651 if (a != NULL)
652 attrib_to_stat(a, &sb);
653 lname = ls_file(fname, &sb, 1);
654 printf("%s\n", lname);
655 xfree(lname);
656 } else {
657 /* XXX - multicolumn display would be nice here */
658 printf("%s\n", fname);
659 }
660 xfree(fname);
661 }
662
663 if (g.gl_pathc)
664 globfree(&g);
665
666 return (0);
667}
668
669static int
670parse_args(const char **cpp, int *pflag, int *lflag,
671 unsigned long *n_arg, char **path1, char **path2)
509{ 672{
510 const char *cmd, *cp = *cpp; 673 const char *cmd, *cp = *cpp;
511 char *cp2; 674 char *cp2;
@@ -545,7 +708,7 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
545 } 708 }
546 709
547 /* Get arguments and parse flags */ 710 /* Get arguments and parse flags */
548 *pflag = *n_arg = 0; 711 *lflag = *pflag = *n_arg = 0;
549 *path1 = *path2 = NULL; 712 *path1 = *path2 = NULL;
550 switch (cmdnum) { 713 switch (cmdnum) {
551 case I_GET: 714 case I_GET:
@@ -592,6 +755,8 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
592 } 755 }
593 break; 756 break;
594 case I_LS: 757 case I_LS:
758 if (parse_ls_flags(&cp, lflag))
759 return(-1);
595 /* Path is optional */ 760 /* Path is optional */
596 if (get_pathname(&cp, path1)) 761 if (get_pathname(&cp, path1))
597 return(-1); 762 return(-1);
@@ -652,7 +817,7 @@ static int
652parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) 817parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
653{ 818{
654 char *path1, *path2, *tmp; 819 char *path1, *path2, *tmp;
655 int pflag, cmdnum, i; 820 int pflag, lflag, cmdnum, i;
656 unsigned long n_arg; 821 unsigned long n_arg;
657 Attrib a, *aa; 822 Attrib a, *aa;
658 char path_buf[MAXPATHLEN]; 823 char path_buf[MAXPATHLEN];
@@ -660,7 +825,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
660 glob_t g; 825 glob_t g;
661 826
662 path1 = path2 = NULL; 827 path1 = path2 = NULL;
663 cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2); 828 cmdnum = parse_args(&cmd, &pflag, &lflag, &n_arg,
829 &path1, &path2);
664 830
665 memset(&g, 0, sizeof(g)); 831 memset(&g, 0, sizeof(g));
666 832
@@ -732,22 +898,18 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
732 break; 898 break;
733 case I_LS: 899 case I_LS:
734 if (!path1) { 900 if (!path1) {
735 do_ls(conn, *pwd); 901 do_globbed_ls(conn, *pwd, *pwd, lflag);
736 break; 902 break;
737 } 903 }
904
905 /* Strip pwd off beginning of non-absolute paths */
906 tmp = NULL;
907 if (*path1 != '/')
908 tmp = *pwd;
909
738 path1 = make_absolute(path1, *pwd); 910 path1 = make_absolute(path1, *pwd);
739 if ((tmp = do_realpath(conn, path1)) == NULL) 911
740 break; 912 do_globbed_ls(conn, path1, tmp, lflag);
741 xfree(path1);
742 path1 = tmp;
743 if ((aa = do_stat(conn, path1, 0)) == NULL)
744 break;
745 if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
746 !S_ISDIR(aa->perm)) {
747 error("Can't ls: \"%s\" is not a directory", path1);
748 break;
749 }
750 do_ls(conn, path1);
751 break; 913 break;
752 case I_LCHDIR: 914 case I_LCHDIR:
753 if (chdir(path1) == -1) { 915 if (chdir(path1) == -1) {
diff --git a/sftp-server.c b/sftp-server.c
index a5c325561..84264693d 100644
--- a/sftp-server.c
+++ b/sftp-server.c
@@ -22,7 +22,7 @@
22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 22 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23 */ 23 */
24#include "includes.h" 24#include "includes.h"
25RCSID("$OpenBSD: sftp-server.c,v 1.37 2002/06/24 17:57:20 deraadt Exp $"); 25RCSID("$OpenBSD: sftp-server.c,v 1.38 2002/09/11 22:41:50 djm Exp $");
26 26
27#include "buffer.h" 27#include "buffer.h"
28#include "bufaux.h" 28#include "bufaux.h"
@@ -695,48 +695,6 @@ process_opendir(void)
695 xfree(path); 695 xfree(path);
696} 696}
697 697
698/*
699 * drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
700 */
701static char *
702ls_file(char *name, struct stat *st)
703{
704 int ulen, glen, sz = 0;
705 struct passwd *pw;
706 struct group *gr;
707 struct tm *ltime = localtime(&st->st_mtime);
708 char *user, *group;
709 char buf[1024], mode[11+1], tbuf[12+1], ubuf[11+1], gbuf[11+1];
710
711 strmode(st->st_mode, mode);
712 if ((pw = getpwuid(st->st_uid)) != NULL) {
713 user = pw->pw_name;
714 } else {
715 snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
716 user = ubuf;
717 }
718 if ((gr = getgrgid(st->st_gid)) != NULL) {
719 group = gr->gr_name;
720 } else {
721 snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
722 group = gbuf;
723 }
724 if (ltime != NULL) {
725 if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
726 sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
727 else
728 sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
729 }
730 if (sz == 0)
731 tbuf[0] = '\0';
732 ulen = MAX(strlen(user), 8);
733 glen = MAX(strlen(group), 8);
734 snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode,
735 st->st_nlink, ulen, user, glen, group,
736 (u_int64_t)st->st_size, tbuf, name);
737 return xstrdup(buf);
738}
739
740static void 698static void
741process_readdir(void) 699process_readdir(void)
742{ 700{
@@ -772,7 +730,7 @@ process_readdir(void)
772 continue; 730 continue;
773 stat_to_attrib(&st, &(stats[count].attrib)); 731 stat_to_attrib(&st, &(stats[count].attrib));
774 stats[count].name = xstrdup(dp->d_name); 732 stats[count].name = xstrdup(dp->d_name);
775 stats[count].long_name = ls_file(dp->d_name, &st); 733 stats[count].long_name = ls_file(dp->d_name, &st, 0);
776 count++; 734 count++;
777 /* send up to 100 entries in one message */ 735 /* send up to 100 entries in one message */
778 /* XXX check packet size instead */ 736 /* XXX check packet size instead */
diff --git a/sftp.1 b/sftp.1
index 0e6d741a9..33ceb6596 100644
--- a/sftp.1
+++ b/sftp.1
@@ -1,4 +1,4 @@
1.\" $OpenBSD: sftp.1,v 1.35 2002/06/20 20:00:05 stevesk Exp $ 1.\" $OpenBSD: sftp.1,v 1.36 2002/09/11 22:41:50 djm Exp $
2.\" 2.\"
3.\" Copyright (c) 2001 Damien Miller. All rights reserved. 3.\" Copyright (c) 2001 Damien Miller. All rights reserved.
4.\" 4.\"
@@ -203,12 +203,18 @@ to
203.Ar newpath . 203.Ar newpath .
204.It Ic lpwd 204.It Ic lpwd
205Print local working directory. 205Print local working directory.
206.It Ic ls Op Ar path 206.It Xo Ic ls
207.Op Ar flags
208.Op Ar path
209.Xc
207Display remote directory listing of either 210Display remote directory listing of either
208.Ar path 211.Ar path
209or current directory if 212or current directory if
210.Ar path 213.Ar path
211is not specified. 214is not specified. If the
215.Fl l
216flag is specified, then display additional details including permissions
217and ownership information.
212.It Ic lumask Ar umask 218.It Ic lumask Ar umask
213Set local umask to 219Set local umask to
214.Ar umask . 220.Ar umask .