[sftp.1 sftp-client.c sftp-client.h sftp-common.c sftp-common.h]
     [sftp-glob.c sftp-glob.h sftp-int.c sftp-server.c]
     support for short/long listings and globbing in "ls"; ok markus@
This commit is contained in:
Damien Miller 2002-09-12 09:54:25 +10:00
Родитель 789e95dbe9
Коммит e1a4981707
10 изменённых файлов: 270 добавлений и 105 удалений

Просмотреть файл

@ -22,6 +22,10 @@
[authfd.c authfd.h ssh.c]
don't connect to agent to test for presence if we've previously
connected; ok markus@
- djm@cvs.openbsd.org 2002/09/11 22:41:50
[sftp.1 sftp-client.c sftp-client.h sftp-common.c sftp-common.h]
[sftp-glob.c sftp-glob.h sftp-int.c sftp-server.c]
support for short/long listings and globbing in "ls"; ok markus@
20020911
- (djm) Sync openbsd-compat with OpenBSD -current
@ -1642,4 +1646,4 @@
- (stevesk) entropy.c: typo in debug message
- (djm) ssh-keygen -i needs seeded RNG; report from markus@
$Id: ChangeLog,v 1.2457 2002/09/11 23:52:46 djm Exp $
$Id: ChangeLog,v 1.2458 2002/09/11 23:54:25 djm Exp $

Просмотреть файл

@ -28,7 +28,7 @@
/* XXX: copy between two remote sites */
#include "includes.h"
RCSID("$OpenBSD: sftp-client.c,v 1.34 2002/06/27 10:35:47 deraadt Exp $");
RCSID("$OpenBSD: sftp-client.c,v 1.35 2002/09/11 22:41:49 djm Exp $");
#include "openbsd-compat/fake-queue.h"
@ -414,12 +414,6 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
return(0);
}
int
do_ls(struct sftp_conn *conn, char *path)
{
return(do_lsreaddir(conn, path, 1, NULL));
}
int
do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
{

Просмотреть файл

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.10 2002/06/23 09:30:14 deraadt Exp $ */
/* $OpenBSD: sftp-client.h,v 1.11 2002/09/11 22:41:50 djm Exp $ */
/*
* Copyright (c) 2001,2002 Damien Miller. All rights reserved.
@ -48,9 +48,6 @@ u_int sftp_proto_version(struct sftp_conn *);
/* Close file referred to by 'handle' */
int do_close(struct sftp_conn *, char *, u_int);
/* List contents of directory 'path' to stdout */
int do_ls(struct sftp_conn *, char *);
/* Read contents of 'path' to NULL-terminated array 'dir' */
int do_readdir(struct sftp_conn *, char *, SFTP_DIRENT ***);

Просмотреть файл

@ -24,7 +24,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-common.c,v 1.6 2002/06/23 09:30:14 deraadt Exp $");
RCSID("$OpenBSD: sftp-common.c,v 1.7 2002/09/11 22:41:50 djm Exp $");
#include "buffer.h"
#include "bufaux.h"
@ -65,6 +65,26 @@ stat_to_attrib(struct stat *st, Attrib *a)
a->mtime = st->st_mtime;
}
/* Convert from filexfer attribs to struct stat */
void
attrib_to_stat(Attrib *a, struct stat *st)
{
memset(st, 0, sizeof(*st));
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
st->st_size = a->size;
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
st->st_uid = a->uid;
st->st_gid = a->gid;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
st->st_mode = a->perm;
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
st->st_atime = a->atime;
st->st_mtime = a->mtime;
}
}
/* Decode attributes in buffer */
Attrib *
decode_attrib(Buffer *b)
@ -149,3 +169,45 @@ fx2txt(int status)
}
/* NOTREACHED */
}
/*
* drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
*/
char *
ls_file(char *name, struct stat *st, int remote)
{
int ulen, glen, sz = 0;
struct passwd *pw;
struct group *gr;
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];
strmode(st->st_mode, mode);
if (!remote && (pw = getpwuid(st->st_uid)) != NULL) {
user = pw->pw_name;
} else {
snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
user = ubuf;
}
if (!remote && (gr = getgrgid(st->st_gid)) != NULL) {
group = gr->gr_name;
} else {
snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
group = gbuf;
}
if (ltime != NULL) {
if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
else
sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
}
if (sz == 0)
tbuf[0] = '\0';
ulen = MAX(strlen(user), 8);
glen = MAX(strlen(group), 8);
snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode,
st->st_nlink, ulen, user, glen, group,
(u_int64_t)st->st_size, tbuf, name);
return xstrdup(buf);
}

Просмотреть файл

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-common.h,v 1.3 2001/06/26 17:27:24 markus Exp $ */
/* $OpenBSD: sftp-common.h,v 1.4 2002/09/11 22:41:50 djm Exp $ */
/*
* Copyright (c) 2001 Markus Friedl. All rights reserved.
@ -40,7 +40,9 @@ struct Attrib {
void attrib_clear(Attrib *);
void stat_to_attrib(struct stat *, Attrib *);
void attrib_to_stat(Attrib *, struct stat *);
Attrib *decode_attrib(Buffer *);
void encode_attrib(Buffer *, Attrib *);
char *ls_file(char *, struct stat *, int);
const char *fx2txt(int);

Просмотреть файл

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-glob.c,v 1.12 2002/07/04 04:15:33 deraadt Exp $");
RCSID("$OpenBSD: sftp-glob.c,v 1.13 2002/09/11 22:41:50 djm Exp $");
#include "buffer.h"
#include "bufaux.h"
@ -107,25 +107,6 @@ fudge_closedir(struct SFTP_OPENDIR *od)
xfree(od);
}
static void
attrib_to_stat(Attrib *a, struct stat *st)
{
memset(st, 0, sizeof(*st));
if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
st->st_size = a->size;
if (a->flags & SSH2_FILEXFER_ATTR_UIDGID) {
st->st_uid = a->uid;
st->st_gid = a->gid;
}
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
st->st_mode = a->perm;
if (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
st->st_atime = a->atime;
st->st_mtime = a->mtime;
}
}
static int
fudge_lstat(const char *path, struct stat *st)
{

Просмотреть файл

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-glob.h,v 1.7 2002/03/19 10:49:35 markus Exp $ */
/* $OpenBSD: sftp-glob.h,v 1.8 2002/09/11 22:41:50 djm Exp $ */
/*
* Copyright (c) 2001,2002 Damien Miller. All rights reserved.
@ -31,8 +31,7 @@
#include "sftp-client.h"
int
remote_glob(struct sftp_conn *, const char *, int,
int remote_glob(struct sftp_conn *, const char *, int,
int (*)(const char *, int), glob_t *);
#endif

Просмотреть файл

@ -22,11 +22,10 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
/* XXX: globbed ls */
/* XXX: recursive operations */
#include "includes.h"
RCSID("$OpenBSD: sftp-int.c,v 1.47 2002/06/23 09:30:14 deraadt Exp $");
RCSID("$OpenBSD: sftp-int.c,v 1.48 2002/09/11 22:41:50 djm Exp $");
#include "buffer.h"
#include "xmalloc.h"
@ -201,6 +200,26 @@ local_do_ls(const char *args)
}
}
/* Strip one path (usually the pwd) from the start of another */
static char *
path_strip(char *path, char *strip)
{
size_t len;
char *ret;
if (strip == NULL)
return (xstrdup(path));
len = strlen(strip);
if (strip != NULL && strncmp(path, strip, len) == 0) {
if (strip[len - 1] != '/' && path[len] == '/')
len++;
return (xstrdup(path + len));
}
return (xstrdup(path));
}
static char *
path_append(char *p1, char *p2)
{
@ -209,7 +228,7 @@ path_append(char *p1, char *p2)
ret = xmalloc(len);
strlcpy(ret, p1, len);
if (strcmp(p1, "/") != 0)
if (p1[strlen(p1) - 1] != '/')
strlcat(ret, "/", len);
strlcat(ret, p2, len);
@ -273,6 +292,29 @@ parse_getput_flags(const char **cpp, int *pflag)
return(0);
}
static int
parse_ls_flags(const char **cpp, int *lflag)
{
const char *cp = *cpp;
/* Check for flags */
if (cp++[0] == '-') {
for(; strchr(WHITESPACE, *cp) == NULL; cp++) {
switch (*cp) {
case 'l':
*lflag = 1;
break;
default:
error("Invalid flag -%c", *cp);
return(-1);
}
}
*cpp = cp + strspn(cp, WHITESPACE);
}
return(0);
}
static int
get_pathname(const char **cpp, char **path)
{
@ -504,8 +546,129 @@ out:
}
static int
parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
char **path1, char **path2)
sdirent_comp(const void *aa, const void *bb)
{
SFTP_DIRENT *a = *(SFTP_DIRENT **)aa;
SFTP_DIRENT *b = *(SFTP_DIRENT **)bb;
return (strcmp(a->filename, b->filename));
}
/* sftp ls.1 replacement for directories */
static int
do_ls_dir(struct sftp_conn *conn, char *path, char *strip_path, int lflag)
{
int n;
SFTP_DIRENT **d;
if ((n = do_readdir(conn, path, &d)) != 0)
return (n);
/* Count entries for sort */
for (n = 0; d[n] != NULL; n++)
;
qsort(d, n, sizeof(*d), sdirent_comp);
for (n = 0; d[n] != NULL; n++) {
char *tmp, *fname;
tmp = path_append(path, d[n]->filename);
fname = path_strip(tmp, strip_path);
xfree(tmp);
if (lflag) {
char *lname;
struct stat sb;
memset(&sb, 0, sizeof(sb));
attrib_to_stat(&d[n]->a, &sb);
lname = ls_file(fname, &sb, 1);
printf("%s\n", lname);
xfree(lname);
} else {
/* XXX - multicolumn display would be nice here */
printf("%s\n", fname);
}
xfree(fname);
}
free_sftp_dirents(d);
return (0);
}
/* sftp ls.1 replacement which handles path globs */
static int
do_globbed_ls(struct sftp_conn *conn, char *path, char *strip_path,
int lflag)
{
glob_t g;
int i;
Attrib *a;
struct stat sb;
memset(&g, 0, sizeof(g));
if (remote_glob(conn, path, GLOB_MARK|GLOB_NOCHECK|GLOB_BRACE,
NULL, &g)) {
error("Can't ls: \"%s\" not found", path);
return (-1);
}
/*
* If the glob returns a single match, which is the same as the
* input glob, and it is a directory, then just list its contents
*/
if (g.gl_pathc == 1 &&
strncmp(path, g.gl_pathv[0], strlen(g.gl_pathv[0]) - 1) == 0) {
if ((a = do_lstat(conn, path, 1)) == NULL) {
globfree(&g);
return (-1);
}
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
S_ISDIR(a->perm)) {
globfree(&g);
return (do_ls_dir(conn, path, strip_path, lflag));
}
}
for (i = 0; g.gl_pathv[i]; i++) {
char *fname, *lname;
fname = path_strip(g.gl_pathv[i], strip_path);
if (lflag) {
/*
* XXX: this is slow - 1 roundtrip per path
* A solution to this is to fork glob() and
* build a sftp specific version which keeps the
* attribs (which currently get thrown away)
* that the server returns as well as the filenames.
*/
memset(&sb, 0, sizeof(sb));
a = do_lstat(conn, g.gl_pathv[i], 1);
if (a != NULL)
attrib_to_stat(a, &sb);
lname = ls_file(fname, &sb, 1);
printf("%s\n", lname);
xfree(lname);
} else {
/* XXX - multicolumn display would be nice here */
printf("%s\n", fname);
}
xfree(fname);
}
if (g.gl_pathc)
globfree(&g);
return (0);
}
static int
parse_args(const char **cpp, int *pflag, int *lflag,
unsigned long *n_arg, char **path1, char **path2)
{
const char *cmd, *cp = *cpp;
char *cp2;
@ -545,7 +708,7 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
}
/* Get arguments and parse flags */
*pflag = *n_arg = 0;
*lflag = *pflag = *n_arg = 0;
*path1 = *path2 = NULL;
switch (cmdnum) {
case I_GET:
@ -592,6 +755,8 @@ parse_args(const char **cpp, int *pflag, unsigned long *n_arg,
}
break;
case I_LS:
if (parse_ls_flags(&cp, lflag))
return(-1);
/* Path is optional */
if (get_pathname(&cp, path1))
return(-1);
@ -652,7 +817,7 @@ static int
parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
{
char *path1, *path2, *tmp;
int pflag, cmdnum, i;
int pflag, lflag, cmdnum, i;
unsigned long n_arg;
Attrib a, *aa;
char path_buf[MAXPATHLEN];
@ -660,7 +825,8 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
glob_t g;
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
cmdnum = parse_args(&cmd, &pflag, &lflag, &n_arg,
&path1, &path2);
memset(&g, 0, sizeof(g));
@ -732,22 +898,18 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd)
break;
case I_LS:
if (!path1) {
do_ls(conn, *pwd);
do_globbed_ls(conn, *pwd, *pwd, lflag);
break;
}
/* Strip pwd off beginning of non-absolute paths */
tmp = NULL;
if (*path1 != '/')
tmp = *pwd;
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(conn, path1)) == NULL)
break;
xfree(path1);
path1 = tmp;
if ((aa = do_stat(conn, path1, 0)) == NULL)
break;
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
!S_ISDIR(aa->perm)) {
error("Can't ls: \"%s\" is not a directory", path1);
break;
}
do_ls(conn, path1);
do_globbed_ls(conn, path1, tmp, lflag);
break;
case I_LCHDIR:
if (chdir(path1) == -1) {

Просмотреть файл

@ -22,7 +22,7 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-server.c,v 1.37 2002/06/24 17:57:20 deraadt Exp $");
RCSID("$OpenBSD: sftp-server.c,v 1.38 2002/09/11 22:41:50 djm Exp $");
#include "buffer.h"
#include "bufaux.h"
@ -695,48 +695,6 @@ process_opendir(void)
xfree(path);
}
/*
* drwxr-xr-x 5 markus markus 1024 Jan 13 18:39 .ssh
*/
static char *
ls_file(char *name, struct stat *st)
{
int ulen, glen, sz = 0;
struct passwd *pw;
struct group *gr;
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];
strmode(st->st_mode, mode);
if ((pw = getpwuid(st->st_uid)) != NULL) {
user = pw->pw_name;
} else {
snprintf(ubuf, sizeof ubuf, "%u", (u_int)st->st_uid);
user = ubuf;
}
if ((gr = getgrgid(st->st_gid)) != NULL) {
group = gr->gr_name;
} else {
snprintf(gbuf, sizeof gbuf, "%u", (u_int)st->st_gid);
group = gbuf;
}
if (ltime != NULL) {
if (time(NULL) - st->st_mtime < (365*24*60*60)/2)
sz = strftime(tbuf, sizeof tbuf, "%b %e %H:%M", ltime);
else
sz = strftime(tbuf, sizeof tbuf, "%b %e %Y", ltime);
}
if (sz == 0)
tbuf[0] = '\0';
ulen = MAX(strlen(user), 8);
glen = MAX(strlen(group), 8);
snprintf(buf, sizeof buf, "%s %3d %-*s %-*s %8llu %s %s", mode,
st->st_nlink, ulen, user, glen, group,
(u_int64_t)st->st_size, tbuf, name);
return xstrdup(buf);
}
static void
process_readdir(void)
{
@ -772,7 +730,7 @@ process_readdir(void)
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);
stats[count].long_name = ls_file(dp->d_name, &st, 0);
count++;
/* send up to 100 entries in one message */
/* XXX check packet size instead */

12
sftp.1
Просмотреть файл

@ -1,4 +1,4 @@
.\" $OpenBSD: sftp.1,v 1.35 2002/06/20 20:00:05 stevesk Exp $
.\" $OpenBSD: sftp.1,v 1.36 2002/09/11 22:41:50 djm Exp $
.\"
.\" Copyright (c) 2001 Damien Miller. All rights reserved.
.\"
@ -203,12 +203,18 @@ to
.Ar newpath .
.It Ic lpwd
Print local working directory.
.It Ic ls Op Ar path
.It Xo Ic ls
.Op Ar flags
.Op Ar path
.Xc
Display remote directory listing of either
.Ar path
or current directory if
.Ar path
is not specified.
is not specified. If the
.Fl l
flag is specified, then display additional details including permissions
and ownership information.
.It Ic lumask Ar umask
Set local umask to
.Ar umask .