mirror of git://anongit.mindrot.org/openssh.git
- 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:
parent
86fe8686b9
commit
c8d1c30c31
|
@ -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 $
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
288
sftp-int.c
288
sftp-int.c
|
@ -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)
|
||||
|
|
Loading…
Reference in New Issue