diff options
-rw-r--r-- | ChangeLog | 6 | ||||
-rw-r--r-- | sftp-client.c | 8 | ||||
-rw-r--r-- | sftp-client.h | 5 | ||||
-rw-r--r-- | sftp-common.c | 64 | ||||
-rw-r--r-- | sftp-common.h | 4 | ||||
-rw-r--r-- | sftp-glob.c | 21 | ||||
-rw-r--r-- | sftp-glob.h | 5 | ||||
-rw-r--r-- | sftp-int.c | 204 | ||||
-rw-r--r-- | sftp-server.c | 46 | ||||
-rw-r--r-- | sftp.1 | 12 |
10 files changed, 270 insertions, 105 deletions
@@ -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 | ||
26 | 20020911 | 30 | 20020911 |
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" |
31 | RCSID("$OpenBSD: sftp-client.c,v 1.34 2002/06/27 10:35:47 deraadt Exp $"); | 31 | RCSID("$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 | ||
417 | int | 417 | int |
418 | do_ls(struct sftp_conn *conn, char *path) | ||
419 | { | ||
420 | return(do_lsreaddir(conn, path, 1, NULL)); | ||
421 | } | ||
422 | |||
423 | int | ||
424 | do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) | 418 | do_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' */ |
49 | int do_close(struct sftp_conn *, char *, u_int); | 49 | int do_close(struct sftp_conn *, char *, u_int); |
50 | 50 | ||
51 | /* List contents of directory 'path' to stdout */ | ||
52 | int 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' */ |
55 | int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***); | 52 | int 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" |
27 | RCSID("$OpenBSD: sftp-common.c,v 1.6 2002/06/23 09:30:14 deraadt Exp $"); | 27 | RCSID("$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 */ | ||
69 | void | ||
70 | attrib_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 */ |
69 | Attrib * | 89 | Attrib * |
70 | decode_attrib(Buffer *b) | 90 | decode_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 | */ | ||
176 | char * | ||
177 | ls_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 | ||
41 | void attrib_clear(Attrib *); | 41 | void attrib_clear(Attrib *); |
42 | void stat_to_attrib(struct stat *, Attrib *); | 42 | void stat_to_attrib(struct stat *, Attrib *); |
43 | void attrib_to_stat(Attrib *, struct stat *); | ||
43 | Attrib *decode_attrib(Buffer *); | 44 | Attrib *decode_attrib(Buffer *); |
44 | void encode_attrib(Buffer *, Attrib *); | 45 | void encode_attrib(Buffer *, Attrib *); |
46 | char *ls_file(char *, struct stat *, int); | ||
45 | 47 | ||
46 | const char *fx2txt(int); | 48 | const 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" |
26 | RCSID("$OpenBSD: sftp-glob.c,v 1.12 2002/07/04 04:15:33 deraadt Exp $"); | 26 | RCSID("$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 | ||
110 | static void | ||
111 | attrib_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 | |||
129 | static int | 110 | static int |
130 | fudge_lstat(const char *path, struct stat *st) | 111 | fudge_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 | ||
34 | int | 34 | int remote_glob(struct sftp_conn *, const char *, int, |
35 | remote_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" |
29 | RCSID("$OpenBSD: sftp-int.c,v 1.47 2002/06/23 09:30:14 deraadt Exp $"); | 28 | RCSID("$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 */ | ||
204 | static char * | ||
205 | path_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 | |||
204 | static char * | 223 | static char * |
205 | path_append(char *p1, char *p2) | 224 | path_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 | ||
276 | static int | 295 | static int |
296 | parse_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 | |||
318 | static int | ||
277 | get_pathname(const char **cpp, char **path) | 319 | get_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 | ||
506 | static int | 548 | static int |
507 | parse_args(const char **cpp, int *pflag, unsigned long *n_arg, | 549 | sdirent_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 */ | ||
558 | static int | ||
559 | do_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 */ | ||
602 | static int | ||
603 | do_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 | |||
669 | static int | ||
670 | parse_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 | |||
652 | parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd) | 817 | parse_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" |
25 | RCSID("$OpenBSD: sftp-server.c,v 1.37 2002/06/24 17:57:20 deraadt Exp $"); | 25 | RCSID("$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 | */ | ||
701 | static char * | ||
702 | ls_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 | |||
740 | static void | 698 | static void |
741 | process_readdir(void) | 699 | process_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 */ |
@@ -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 |
205 | Print local working directory. | 205 | Print 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 | ||
207 | Display remote directory listing of either | 210 | Display remote directory listing of either |
208 | .Ar path | 211 | .Ar path |
209 | or current directory if | 212 | or current directory if |
210 | .Ar path | 213 | .Ar path |
211 | is not specified. | 214 | is not specified. If the |
215 | .Fl l | ||
216 | flag is specified, then display additional details including permissions | ||
217 | and ownership information. | ||
212 | .It Ic lumask Ar umask | 218 | .It Ic lumask Ar umask |
213 | Set local umask to | 219 | Set local umask to |
214 | .Ar umask . | 220 | .Ar umask . |