- djm@cvs.openbsd.org 2001/03/16 08:16:18

[sftp-client.c sftp-client.h sftp-glob.c sftp-int.c]
     Revise globbing for get/put to be more shell-like. In particular,
     "get/put file* directory/" now works. ok markus@
This commit is contained in:
Ben Lindstrom 2001-03-17 00:34:46 +00:00
parent 86fe8686b9
commit c8d1c30c31
5 changed files with 249 additions and 93 deletions

View File

@ -8,6 +8,10 @@
- markus@cvs.openbsd.org 2001/03/15 22:07:08
[session.c]
pass Session to do_child + KNF
- djm@cvs.openbsd.org 2001/03/16 08:16:18
[sftp-client.c sftp-client.h sftp-glob.c sftp-int.c]
Revise globbing for get/put to be more shell-like. In particular,
"get/put file* directory/" now works. ok markus@
20010315
- OpenBSD CVS Sync
@ -4570,4 +4574,4 @@
- Wrote replacements for strlcpy and mkdtemp
- Released 1.0pre1
$Id: ChangeLog,v 1.963 2001/03/17 00:32:57 mouring Exp $
$Id: ChangeLog,v 1.964 2001/03/17 00:34:46 mouring Exp $

View File

@ -29,7 +29,7 @@
/* XXX: copy between two remote sites */
#include "includes.h"
RCSID("$OpenBSD: sftp-client.c,v 1.13 2001/03/14 08:57:14 markus Exp $");
RCSID("$OpenBSD: sftp-client.c,v 1.14 2001/03/16 08:16:17 djm Exp $");
#include "ssh.h"
#include "buffer.h"
@ -180,7 +180,7 @@ get_handle(int fd, u_int expected_id, u_int *len)
}
Attrib *
get_decode_stat(int fd, u_int expected_id)
get_decode_stat(int fd, u_int expected_id, int quiet)
{
Buffer msg;
u_int type, id;
@ -198,7 +198,10 @@ get_decode_stat(int fd, u_int expected_id)
if (type == SSH2_FXP_STATUS) {
int status = buffer_get_int(&msg);
error("Couldn't stat remote file: %s", fx2txt(status));
if (quiet)
debug("Couldn't stat remote file: %s", fx2txt(status));
else
error("Couldn't stat remote file: %s", fx2txt(status));
return(NULL);
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%d) packet, got %d",
@ -455,34 +458,33 @@ do_rmdir(int fd_in, int fd_out, char *path)
}
Attrib *
do_stat(int fd_in, int fd_out, char *path)
do_stat(int fd_in, int fd_out, char *path, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_STAT, path, strlen(path));
return(get_decode_stat(fd_in, id));
return(get_decode_stat(fd_in, id, quiet));
}
Attrib *
do_lstat(int fd_in, int fd_out, char *path)
do_lstat(int fd_in, int fd_out, char *path, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_LSTAT, path, strlen(path));
return(get_decode_stat(fd_in, id));
return(get_decode_stat(fd_in, id, quiet));
}
Attrib *
do_fstat(int fd_in, int fd_out, char *handle,
u_int handle_len)
do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len, int quiet)
{
u_int id;
id = msg_id++;
send_string_request(fd_out, id, SSH2_FXP_FSTAT, handle, handle_len);
return(get_decode_stat(fd_in, id));
return(get_decode_stat(fd_in, id, quiet));
}
int
@ -677,7 +679,7 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
Attrib junk, *a;
int status;
a = do_stat(fd_in, fd_out, remote_path);
a = do_stat(fd_in, fd_out, remote_path, 0);
if (a == NULL)
return(-1);
@ -687,11 +689,17 @@ do_download(int fd_in, int fd_out, char *remote_path, char *local_path,
else
mode = 0666;
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(a->perm & S_IFDIR)) {
error("Cannot download a directory: %s", remote_path);
return(-1);
}
local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, mode);
if (local_fd == -1) {
error("Couldn't open local file \"%s\" for writing: %s",
local_path, strerror(errno));
return(errno);
return(-1);
}
buffer_init(&msg);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.3 2001/03/13 22:42:54 djm Exp $ */
/* $OpenBSD: sftp-client.h,v 1.4 2001/03/16 08:16:18 djm Exp $ */
/*
* Copyright (c) 2001 Damien Miller. All rights reserved.
@ -62,14 +62,14 @@ int do_mkdir(int fd_in, int fd_out, char *path, Attrib *a);
int do_rmdir(int fd_in, int fd_out, char *path);
/* Get file attributes of 'path' (follows symlinks) */
Attrib *do_stat(int fd_in, int fd_out, char *path);
Attrib *do_stat(int fd_in, int fd_out, char *path, int quiet);
/* Get file attributes of 'path' (does not follow symlinks) */
Attrib *do_lstat(int fd_in, int fd_out, char *path);
Attrib *do_lstat(int fd_in, int fd_out, char *path, int quiet);
/* Get file attributes of open file 'handle' */
Attrib *do_fstat(int fd_in, int fd_out, char *handle,
u_int handle_len);
Attrib *do_fstat(int fd_in, int fd_out, char *handle, u_int handle_len,
int quiet);
/* Set file attributes of 'path' */
int do_setstat(int fd_in, int fd_out, char *path, Attrib *a);

View File

@ -23,7 +23,7 @@
*/
#include "includes.h"
RCSID("$OpenBSD: sftp-glob.c,v 1.1 2001/03/13 22:42:54 djm Exp $");
RCSID("$OpenBSD: sftp-glob.c,v 1.2 2001/03/16 08:16:18 djm Exp $");
#include "ssh.h"
#include "buffer.h"
@ -119,7 +119,7 @@ int fudge_lstat(const char *path, struct stat *st)
{
Attrib *a;
if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path)))
if (!(a = do_lstat(cur.fd_in, cur.fd_out, (char*)path, 0)))
return(-1);
attrib_to_stat(a, st);
@ -131,7 +131,7 @@ int fudge_stat(const char *path, struct stat *st)
{
Attrib *a;
if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path)))
if (!(a = do_stat(cur.fd_in, cur.fd_out, (char*)path, 0)))
return(-1);
attrib_to_stat(a, st);

View File

@ -26,7 +26,7 @@
/* XXX: recursive operations */
#include "includes.h"
RCSID("$OpenBSD: sftp-int.c,v 1.28 2001/03/14 15:15:58 markus Exp $");
RCSID("$OpenBSD: sftp-int.c,v 1.29 2001/03/16 08:16:18 djm Exp $");
#include "buffer.h"
#include "xmalloc.h"
@ -194,19 +194,51 @@ local_do_ls(const char *args)
}
}
char *
path_append(char *p1, char *p2)
{
char *ret;
ret = xmalloc(strlen(p1) + strlen(p2) + 2);
strcpy(ret, p1);
strcat(ret, "/");
strcat(ret, p2);
return(ret);
}
char *
make_absolute(char *p, char *pwd)
{
char buf[2048];
char *abs;
/* Derelativise */
if (p && p[0] != '/') {
snprintf(buf, sizeof(buf), "%s/%s", pwd, p);
abs = path_append(pwd, p);
xfree(p);
p = xstrdup(buf);
return(abs);
} else
return(p);
}
int
infer_path(const char *p, char **ifp)
{
char *cp;
cp = strrchr(p, '/');
if (cp == NULL) {
*ifp = xstrdup(p);
return(0);
}
return(p);
if (!cp[1]) {
error("Invalid path");
return(-1);
}
*ifp = xstrdup(cp + 1);
return(0);
}
int
@ -281,23 +313,182 @@ get_pathname(const char **cpp, char **path)
}
int
infer_path(const char *p, char **ifp)
is_dir(char *path)
{
char *cp;
struct stat sb;
cp = strrchr(p, '/');
if (cp == NULL) {
*ifp = xstrdup(p);
/* XXX: report errors? */
if (stat(path, &sb) == -1)
return(0);
return(sb.st_mode & S_IFDIR);
}
int
remote_is_dir(int in, int out, char *path)
{
Attrib *a;
/* XXX: report errors? */
if ((a = do_stat(in, out, path, 1)) == NULL)
return(0);
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
return(0);
return(a->perm & S_IFDIR);
}
int
process_get(int in, int out, char *src, char *dst, char *pwd, int pflag)
{
char *abs_src = NULL;
char *abs_dst = NULL;
char *tmp;
glob_t g;
int err = 0;
int i;
abs_src = xstrdup(src);
abs_src = make_absolute(abs_src, pwd);
memset(&g, '\0', sizeof(g));
debug3("Looking up %s", abs_src);
if (remote_glob(in, out, abs_src, 0, NULL, &g)) {
error("File \"%s\" not found.", abs_src);
err = -1;
goto out;
}
if (!cp[1]) {
error("Invalid path");
return(-1);
/* Only one match, dst may be file, directory or unspecified */
if (g.gl_pathv[0] && g.gl_matchc == 1) {
if (dst) {
/* If directory specified, append filename */
if (is_dir(dst)) {
if (infer_path(g.gl_pathv[0], &tmp)) {
err = 1;
goto out;
}
abs_dst = path_append(dst, tmp);
xfree(tmp);
} else
abs_dst = xstrdup(dst);
} else if (infer_path(g.gl_pathv[0], &abs_dst)) {
err = -1;
goto out;
}
printf("Fetching %s to %s\n", g.gl_pathv[0], abs_dst);
err = do_download(in, out, g.gl_pathv[0], abs_dst, pflag);
goto out;
}
*ifp = xstrdup(cp + 1);
return(0);
/* Multiple matches, dst may be directory or unspecified */
if (dst && !is_dir(dst)) {
error("Multiple files match, but \"%s\" is not a directory",
dst);
err = -1;
goto out;
}
for(i = 0; g.gl_pathv[i]; i++) {
if (infer_path(g.gl_pathv[i], &tmp)) {
err = -1;
goto out;
}
if (dst) {
abs_dst = path_append(dst, tmp);
xfree(tmp);
} else
abs_dst = tmp;
printf("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (do_download(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
err = -1;
xfree(abs_dst);
abs_dst = NULL;
}
out:
xfree(abs_src);
if (abs_dst)
xfree(abs_dst);
globfree(&g);
return(err);
}
int
process_put(int in, int out, char *src, char *dst, char *pwd, int pflag)
{
char *tmp_dst = NULL;
char *abs_dst = NULL;
char *tmp;
glob_t g;
int err = 0;
int i;
if (dst) {
tmp_dst = xstrdup(dst);
tmp_dst = make_absolute(tmp_dst, pwd);
}
memset(&g, '\0', sizeof(g));
debug3("Looking up %s", src);
if (glob(src, 0, NULL, &g)) {
error("File \"%s\" not found.", src);
err = -1;
goto out;
}
/* Only one match, dst may be file, directory or unspecified */
if (g.gl_pathv[0] && g.gl_matchc == 1) {
if (tmp_dst) {
/* If directory specified, append filename */
if (remote_is_dir(in, out, tmp_dst)) {
if (infer_path(g.gl_pathv[0], &tmp)) {
err = 1;
goto out;
}
abs_dst = path_append(tmp_dst, tmp);
xfree(tmp);
} else
abs_dst = xstrdup(tmp_dst);
} else if (infer_path(g.gl_pathv[0], &abs_dst)) {
err = -1;
goto out;
}
printf("Uploading %s to %s\n", g.gl_pathv[0], abs_dst);
err = do_upload(in, out, g.gl_pathv[0], abs_dst, pflag);
goto out;
}
/* Multiple matches, dst may be directory or unspecified */
if (tmp_dst && !remote_is_dir(in, out, tmp_dst)) {
error("Multiple files match, but \"%s\" is not a directory",
tmp_dst);
err = -1;
goto out;
}
for(i = 0; g.gl_pathv[i]; i++) {
if (infer_path(g.gl_pathv[i], &tmp)) {
err = -1;
goto out;
}
if (tmp_dst) {
abs_dst = path_append(tmp_dst, tmp);
xfree(tmp);
} else
abs_dst = make_absolute(tmp, pwd);
printf("Uploading %s to %s\n", g.gl_pathv[i], abs_dst);
if (do_upload(in, out, g.gl_pathv[i], abs_dst, pflag) == -1)
err = -1;
}
out:
if (abs_dst)
xfree(abs_dst);
if (tmp_dst)
xfree(tmp_dst);
return(err);
}
int
@ -459,66 +650,17 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path1 = path2 = NULL;
cmdnum = parse_args(&cmd, &pflag, &n_arg, &path1, &path2);
memset(&g, 0, sizeof(g));
/* Perform command */
switch (cmdnum) {
case -1:
break;
case I_GET:
memset(&g, 0, sizeof(g));
if (!remote_glob(in, out, path1, 0, NULL, &g)) {
if (path2) {
/* XXX: target should be directory */
error("You cannot specify a target when "
"downloading multiple files");
err = -1;
break;
}
for(i = 0; g.gl_pathv[i]; i++) {
if (!infer_path(g.gl_pathv[i], &path2)) {
printf("Fetching %s\n", g.gl_pathv[i]);
if (do_download(in, out, g.gl_pathv[i],
path2, pflag) == -1)
err = -1;
free(path2);
path2 = NULL;
} else
err = -1;
}
} else {
if (!path2 && infer_path(path1, &path2)) {
err = -1;
break;
}
err = do_download(in, out, path1, path2, pflag);
}
err = process_get(in, out, path1, path2, *pwd, pflag);
break;
case I_PUT:
if (!glob(path1, 0, NULL, &g)) {
if (path2) {
error("You cannot specify a target when "
"uploading multiple files");
err = -1;
break;
}
for(i = 0; g.gl_pathv[i]; i++) {
if (!infer_path(g.gl_pathv[i], &path2)) {
path2 = make_absolute(path2, *pwd);
printf("Uploading %s\n", g.gl_pathv[i]);
if (do_upload(in, out, g.gl_pathv[i],
path2, pflag) == -1)
err = -1;
free(path2);
path2 = NULL;
} else
err = -1;
}
} else {
if (!path2 && infer_path(path1, &path2)) {
err = -1;
break;
}
err = do_upload(in, out, path1, path2, pflag);
}
err = process_put(in, out, path1, path2, *pwd, pflag);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
@ -561,7 +703,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
err = 1;
break;
}
if ((aa = do_stat(in, out, tmp)) == NULL) {
if ((aa = do_stat(in, out, tmp, 0)) == NULL) {
xfree(tmp);
err = 1;
break;
@ -592,7 +734,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
break;
xfree(path1);
path1 = tmp;
if ((aa = do_stat(in, out, path1)) == NULL)
if ((aa = do_stat(in, out, path1, 0)) == NULL)
break;
if ((aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
!S_ISDIR(aa->perm)) {
@ -640,7 +782,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
if (!(aa = do_stat(in, out, g.gl_pathv[i])))
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
continue;
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
@ -657,7 +799,7 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
path1 = make_absolute(path1, *pwd);
remote_glob(in, out, path1, GLOB_NOCHECK, NULL, &g);
for(i = 0; g.gl_pathv[i]; i++) {
if (!(aa = do_stat(in, out, g.gl_pathv[i])))
if (!(aa = do_stat(in, out, g.gl_pathv[i], 0)))
continue;
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
@ -693,6 +835,8 @@ parse_dispatch_command(int in, int out, const char *cmd, char **pwd)
fatal("%d is not implemented", cmdnum);
}
if (g.gl_pathc)
globfree(&g);
if (path1)
xfree(path1);
if (path2)