upstream: the sftp code was one of my first contributions to

OpenSSH and it shows - the function names are terrible.

Rename do_blah() to sftp_blah() to make them less so.

Completely mechanical except for sftp_stat() and sftp_lstat() which
change from returning a pointer to a static variable (error-prone) to
taking a pointer to a caller-provided receiver.

OpenBSD-Commit-ID: eb54d6a72d0bbba4d623e2175cf5cc4c75dc2ba4
This commit is contained in:
djm@openbsd.org 2023-09-08 05:56:13 +00:00 committed by Damien Miller
parent 249d8bd047
commit 2de990142a
No known key found for this signature in database
6 changed files with 302 additions and 298 deletions

44
scp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: scp.c,v 1.257 2023/07/14 05:31:44 djm Exp $ */ /* $OpenBSD: scp.c,v 1.258 2023/09/08 05:56:13 djm Exp $ */
/* /*
* scp - secure remote copy. This is basically patched BSD rcp which * scp - secure remote copy. This is basically patched BSD rcp which
* uses ssh to do the data transfer (instead of using rcmd). * uses ssh to do the data transfer (instead of using rcmd).
@ -1028,7 +1028,7 @@ do_sftp_connect(char *host, char *user, int port, char *sftp_direct,
reminp, remoutp, pidp) < 0) reminp, remoutp, pidp) < 0)
return NULL; return NULL;
} }
return do_init(*reminp, *remoutp, return sftp_init(*reminp, *remoutp,
sftp_copy_buflen, sftp_nrequests, limit_kbps); sftp_copy_buflen, sftp_nrequests, limit_kbps);
} }
@ -1324,8 +1324,8 @@ prepare_remote_path(struct sftp_conn *conn, const char *path)
return xstrdup("."); return xstrdup(".");
return xstrdup(path + 2 + nslash); return xstrdup(path + 2 + nslash);
} }
if (can_expand_path(conn)) if (sftp_can_expand_path(conn))
return do_expand_path(conn, path); return sftp_expand_path(conn, path);
/* No protocol extension */ /* No protocol extension */
error("server expand-path extension is required " error("server expand-path extension is required "
"for ~user paths in SFTP mode"); "for ~user paths in SFTP mode");
@ -1353,17 +1353,17 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
*/ */
if ((target = prepare_remote_path(conn, targ)) == NULL) if ((target = prepare_remote_path(conn, targ)) == NULL)
cleanup_exit(255); cleanup_exit(255);
target_is_dir = remote_is_dir(conn, target); target_is_dir = sftp_remote_is_dir(conn, target);
if (targetshouldbedirectory && !target_is_dir) { if (targetshouldbedirectory && !target_is_dir) {
debug("target directory \"%s\" does not exist", target); debug("target directory \"%s\" does not exist", target);
a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS; a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = st.st_mode | 0700; /* ensure writable */ a.perm = st.st_mode | 0700; /* ensure writable */
if (do_mkdir(conn, target, &a, 1) != 0) if (sftp_mkdir(conn, target, &a, 1) != 0)
cleanup_exit(255); /* error already logged */ cleanup_exit(255); /* error already logged */
target_is_dir = 1; target_is_dir = 1;
} }
if (target_is_dir) if (target_is_dir)
abs_dst = path_append(target, filename); abs_dst = sftp_path_append(target, filename);
else { else {
abs_dst = target; abs_dst = target;
target = NULL; target = NULL;
@ -1371,12 +1371,12 @@ source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn)
debug3_f("copying local %s to remote %s", src, abs_dst); debug3_f("copying local %s to remote %s", src, abs_dst);
if (src_is_dir && iamrecursive) { if (src_is_dir && iamrecursive) {
if (upload_dir(conn, src, abs_dst, pflag, if (sftp_upload_dir(conn, src, abs_dst, pflag,
SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) { SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
error("failed to upload directory %s to %s", src, targ); error("failed to upload directory %s to %s", src, targ);
errs = 1; errs = 1;
} }
} else if (do_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) { } else if (sftp_upload(conn, src, abs_dst, pflag, 0, 0, 1) != 0) {
error("failed to upload file %s to %s", src, targ); error("failed to upload file %s to %s", src, targ);
errs = 1; errs = 1;
} }
@ -1585,7 +1585,7 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
* a GLOB_NOCHECK result. Check whether the unglobbed path * a GLOB_NOCHECK result. Check whether the unglobbed path
* exists so we can give a nice error message early. * exists so we can give a nice error message early.
*/ */
if (do_stat(conn, g.gl_pathv[0], 1) == NULL) { if (sftp_stat(conn, g.gl_pathv[0], 1, NULL) != 0) {
error("%s: %s", src, strerror(ENOENT)); error("%s: %s", src, strerror(ENOENT));
err = -1; err = -1;
goto out; goto out;
@ -1621,17 +1621,17 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
} }
if (dst_is_dir) if (dst_is_dir)
abs_dst = path_append(dst, filename); abs_dst = sftp_path_append(dst, filename);
else else
abs_dst = xstrdup(dst); abs_dst = xstrdup(dst);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst,
pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1) NULL, pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
err = -1; err = -1;
} else { } else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, if (sftp_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag, 0, 0, 1) == -1) pflag, 0, 0, 1) == -1)
err = -1; err = -1;
} }
@ -1993,7 +1993,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
cleanup_exit(255); cleanup_exit(255);
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
targetisdir = remote_is_dir(to, target); targetisdir = sftp_remote_is_dir(to, target);
if (!targetisdir && targetshouldbedirectory) { if (!targetisdir && targetshouldbedirectory) {
error("%s: destination is not a directory", targ); error("%s: destination is not a directory", targ);
err = -1; err = -1;
@ -2018,7 +2018,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
* a GLOB_NOCHECK result. Check whether the unglobbed path * a GLOB_NOCHECK result. Check whether the unglobbed path
* exists so we can give a nice error message early. * exists so we can give a nice error message early.
*/ */
if (do_stat(from, g.gl_pathv[0], 1) == NULL) { if (sftp_stat(from, g.gl_pathv[0], 1, NULL) != 0) {
error("%s: %s", src, strerror(ENOENT)); error("%s: %s", src, strerror(ENOENT));
err = -1; err = -1;
goto out; goto out;
@ -2034,18 +2034,18 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
} }
if (targetisdir) if (targetisdir)
abs_dst = path_append(target, filename); abs_dst = sftp_path_append(target, filename);
else else
abs_dst = xstrdup(target); abs_dst = xstrdup(target);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst); debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) { if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (crossload_dir(from, to, g.gl_pathv[i], abs_dst, if (sftp_crossload_dir(from, to, g.gl_pathv[i], abs_dst,
NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1) NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1)
err = -1; err = -1;
} else { } else {
if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL, if (sftp_crossload(from, to, g.gl_pathv[i], abs_dst,
pflag) == -1) NULL, pflag) == -1)
err = -1; err = -1;
} }
free(abs_dst); free(abs_dst);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.c,v 1.172 2023/09/08 05:50:12 djm Exp $ */ /* $OpenBSD: sftp-client.c,v 1.173 2023/09/08 05:56:13 djm Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
* *
@ -342,16 +342,17 @@ get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
return handle; return handle;
} }
/* XXX returning &static is error-prone. Refactor to fill *Attrib argument */ static int
static Attrib * get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet, Attrib *a)
get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int id; u_int id;
u_char type; u_char type;
int r; int r;
static Attrib a; Attrib attr;
if (a != NULL)
memset(a, '\0', sizeof(*a));
if ((msg = sshbuf_new()) == NULL) if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed"); fatal_f("sshbuf_new failed");
get_msg(conn, msg); get_msg(conn, msg);
@ -372,21 +373,24 @@ get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
else else
error("stat remote: %s", fx2txt(status)); error("stat remote: %s", fx2txt(status));
sshbuf_free(msg); sshbuf_free(msg);
return(NULL); return -1;
} else if (type != SSH2_FXP_ATTRS) { } else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
SSH2_FXP_ATTRS, type); SSH2_FXP_ATTRS, type);
} }
if ((r = decode_attrib(msg, &a)) != 0) { if ((r = decode_attrib(msg, &attr)) != 0) {
error_fr(r, "decode_attrib"); error_fr(r, "decode_attrib");
sshbuf_free(msg); sshbuf_free(msg);
return NULL; return -1;
} }
/* success */
if (a != NULL)
*a = attr;
debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o", debug3("Received stat reply T:%u I:%u F:0x%04x M:%05o",
type, id, a.flags, a.perm); type, id, attr.flags, attr.perm);
sshbuf_free(msg); sshbuf_free(msg);
return &a; return 0;
} }
static int static int
@ -449,7 +453,7 @@ get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
} }
struct sftp_conn * struct sftp_conn *
do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, sftp_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
u_int64_t limit_kbps) u_int64_t limit_kbps)
{ {
u_char type; u_char type;
@ -560,7 +564,7 @@ do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
/* Query the server for its limits */ /* Query the server for its limits */
if (ret->exts & SFTP_EXT_LIMITS) { if (ret->exts & SFTP_EXT_LIMITS) {
struct sftp_limits limits; struct sftp_limits limits;
if (do_limits(ret, &limits) != 0) if (sftp_get_limits(ret, &limits) != 0)
fatal_f("limits failed"); fatal_f("limits failed");
/* If the caller did not specify, find a good value */ /* If the caller did not specify, find a good value */
@ -614,7 +618,7 @@ sftp_proto_version(struct sftp_conn *conn)
} }
int int
do_limits(struct sftp_conn *conn, struct sftp_limits *limits) sftp_get_limits(struct sftp_conn *conn, struct sftp_limits *limits)
{ {
u_int id, msg_id; u_int id, msg_id;
u_char type; u_char type;
@ -668,7 +672,7 @@ do_limits(struct sftp_conn *conn, struct sftp_limits *limits)
} }
int int
do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len) sftp_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
{ {
u_int id, status; u_int id, status;
struct sshbuf *msg; struct sshbuf *msg;
@ -696,7 +700,7 @@ do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
static int static int
do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag, sftp_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
SFTP_DIRENT ***dir) SFTP_DIRENT ***dir)
{ {
struct sshbuf *msg; struct sshbuf *msg;
@ -821,16 +825,16 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
out: out:
sshbuf_free(msg); sshbuf_free(msg);
do_close(conn, handle, handle_len); sftp_close(conn, handle, handle_len);
free(handle); free(handle);
if (status != 0 && dir != NULL) { if (status != 0 && dir != NULL) {
/* Don't return results on error */ /* Don't return results on error */
free_sftp_dirents(*dir); sftp_free_dirents(*dir);
*dir = NULL; *dir = NULL;
} else if (interrupted && dir != NULL && *dir != NULL) { } else if (interrupted && dir != NULL && *dir != NULL) {
/* Don't return partial matches on interrupt */ /* Don't return partial matches on interrupt */
free_sftp_dirents(*dir); sftp_free_dirents(*dir);
*dir = xcalloc(1, sizeof(**dir)); *dir = xcalloc(1, sizeof(**dir));
**dir = NULL; **dir = NULL;
} }
@ -839,12 +843,12 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
} }
int int
do_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir) sftp_readdir(struct sftp_conn *conn, const char *path, SFTP_DIRENT ***dir)
{ {
return(do_lsreaddir(conn, path, 0, dir)); return sftp_lsreaddir(conn, path, 0, dir);
} }
void free_sftp_dirents(SFTP_DIRENT **s) void sftp_free_dirents(SFTP_DIRENT **s)
{ {
int i; int i;
@ -859,7 +863,7 @@ void free_sftp_dirents(SFTP_DIRENT **s)
} }
int int
do_rm(struct sftp_conn *conn, const char *path) sftp_rm(struct sftp_conn *conn, const char *path)
{ {
u_int status, id; u_int status, id;
@ -874,7 +878,7 @@ do_rm(struct sftp_conn *conn, const char *path)
} }
int int
do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag) sftp_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
{ {
u_int status, id; u_int status, id;
@ -892,7 +896,7 @@ do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
} }
int int
do_rmdir(struct sftp_conn *conn, const char *path) sftp_rmdir(struct sftp_conn *conn, const char *path)
{ {
u_int status, id; u_int status, id;
@ -909,8 +913,8 @@ do_rmdir(struct sftp_conn *conn, const char *path)
return status == SSH2_FX_OK ? 0 : -1; return status == SSH2_FX_OK ? 0 : -1;
} }
Attrib * int
do_stat(struct sftp_conn *conn, const char *path, int quiet) sftp_stat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
{ {
u_int id; u_int id;
@ -922,33 +926,31 @@ do_stat(struct sftp_conn *conn, const char *path, int quiet)
conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
path, strlen(path)); path, strlen(path));
return(get_decode_stat(conn, id, quiet)); return get_decode_stat(conn, id, quiet, a);
} }
Attrib * int
do_lstat(struct sftp_conn *conn, const char *path, int quiet) sftp_lstat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
{ {
u_int id; u_int id;
if (conn->version == 0) { if (conn->version == 0) {
if (quiet) do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
debug("Server version does not support lstat operation"); "Server version does not support lstat operation");
else return sftp_stat(conn, path, quiet, a);
logit("Server version does not support lstat operation");
return(do_stat(conn, path, quiet));
} }
id = conn->msg_id++; id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_LSTAT, path, send_string_request(conn, id, SSH2_FXP_LSTAT, path,
strlen(path)); strlen(path));
return(get_decode_stat(conn, id, quiet)); return get_decode_stat(conn, id, quiet, a);
} }
#ifdef notyet #ifdef notyet
Attrib * int
do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, sftp_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
int quiet) int quiet, Attrib *a)
{ {
u_int id; u_int id;
@ -958,12 +960,12 @@ do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
send_string_request(conn, id, SSH2_FXP_FSTAT, handle, send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
handle_len); handle_len);
return(get_decode_stat(conn, id, quiet)); return get_decode_stat(conn, id, quiet, a);
} }
#endif #endif
int int
do_setstat(struct sftp_conn *conn, const char *path, Attrib *a) sftp_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
{ {
u_int status, id; u_int status, id;
@ -981,7 +983,7 @@ do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
} }
int int
do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len, sftp_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
Attrib *a) Attrib *a)
{ {
u_int status, id; u_int status, id;
@ -1001,7 +1003,7 @@ do_fsetstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
/* Implements both the realpath and expand-path operations */ /* Implements both the realpath and expand-path operations */
static char * static char *
do_realpath_expand(struct sftp_conn *conn, const char *path, int expand) sftp_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int expected_id, count, id; u_int expected_id, count, id;
@ -1076,31 +1078,31 @@ do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
} }
char * char *
do_realpath(struct sftp_conn *conn, const char *path) sftp_realpath(struct sftp_conn *conn, const char *path)
{ {
return do_realpath_expand(conn, path, 0); return sftp_realpath_expand(conn, path, 0);
} }
int int
can_expand_path(struct sftp_conn *conn) sftp_can_expand_path(struct sftp_conn *conn)
{ {
return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0; return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;
} }
char * char *
do_expand_path(struct sftp_conn *conn, const char *path) sftp_expand_path(struct sftp_conn *conn, const char *path)
{ {
if (!can_expand_path(conn)) { if (!sftp_can_expand_path(conn)) {
debug3_f("no server support, fallback to realpath"); debug3_f("no server support, fallback to realpath");
return do_realpath_expand(conn, path, 0); return sftp_realpath_expand(conn, path, 0);
} }
return do_realpath_expand(conn, path, 1); return sftp_realpath_expand(conn, path, 1);
} }
int int
do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath) sftp_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
{ {
Attrib junk, *a; Attrib junk, attr;
struct sshbuf *msg; struct sshbuf *msg;
u_char *old_handle, *new_handle; u_char *old_handle, *new_handle;
u_int mode, status, id; u_int mode, status, id;
@ -1114,14 +1116,14 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
} }
/* Make sure the file exists, and we can copy its perms */ /* Make sure the file exists, and we can copy its perms */
if ((a = do_stat(conn, oldpath, 0)) == NULL) if (sftp_stat(conn, oldpath, 0, &attr) != 0)
return -1; return -1;
/* Do not preserve set[ug]id here, as we do not preserve ownership */ /* Do not preserve set[ug]id here, as we do not preserve ownership */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) { if (attr.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
mode = a->perm & 0777; mode = attr.perm & 0777;
if (!S_ISREG(a->perm)) { if (!S_ISREG(attr.perm)) {
error("Cannot copy non-regular file: %s", oldpath); error("Cannot copy non-regular file: %s", oldpath);
return -1; return -1;
} }
@ -1131,9 +1133,9 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
} }
/* Set up the new perms for the new file */ /* Set up the new perms for the new file */
attrib_clear(a); attrib_clear(&attr);
a->perm = mode; attr.perm = mode;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; attr.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
if ((msg = sshbuf_new()) == NULL) if ((msg = sshbuf_new()) == NULL)
fatal("%s: sshbuf_new failed", __func__); fatal("%s: sshbuf_new failed", __func__);
@ -1167,7 +1169,7 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
(r = sshbuf_put_cstring(msg, newpath)) != 0 || (r = sshbuf_put_cstring(msg, newpath)) != 0 ||
(r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT| (r = sshbuf_put_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
SSH2_FXF_TRUNC)) != 0 || SSH2_FXF_TRUNC)) != 0 ||
(r = encode_attrib(msg, a)) != 0) (r = encode_attrib(msg, &attr)) != 0)
fatal("%s: buffer error: %s", __func__, ssh_err(r)); fatal("%s: buffer error: %s", __func__, ssh_err(r));
send_msg(conn, msg); send_msg(conn, msg);
debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath); debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, newpath);
@ -1204,8 +1206,8 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
/* Clean up everything */ /* Clean up everything */
sshbuf_free(msg); sshbuf_free(msg);
do_close(conn, old_handle, old_handle_len); sftp_close(conn, old_handle, old_handle_len);
do_close(conn, new_handle, new_handle_len); sftp_close(conn, new_handle, new_handle_len);
free(old_handle); free(old_handle);
free(new_handle); free(new_handle);
@ -1213,7 +1215,7 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
} }
int int
do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath, sftp_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
int force_legacy) int force_legacy)
{ {
struct sshbuf *msg; struct sshbuf *msg;
@ -1258,7 +1260,7 @@ do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
} }
int int
do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) sftp_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int status, id; u_int status, id;
@ -1296,7 +1298,7 @@ do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
} }
int int
do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath) sftp_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int status, id; u_int status, id;
@ -1332,7 +1334,7 @@ do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
} }
int int
do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len) sftp_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int status, id; u_int status, id;
@ -1365,7 +1367,7 @@ do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
#ifdef notyet #ifdef notyet
char * char *
do_readlink(struct sftp_conn *conn, const char *path) sftp_readlink(struct sftp_conn *conn, const char *path)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int expected_id, count, id; u_int expected_id, count, id;
@ -1423,7 +1425,7 @@ do_readlink(struct sftp_conn *conn, const char *path)
#endif #endif
int int
do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, sftp_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
int quiet) int quiet)
{ {
struct sshbuf *msg; struct sshbuf *msg;
@ -1454,7 +1456,7 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
#ifdef notyet #ifdef notyet
int int
do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len, sftp_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
struct sftp_statvfs *st, int quiet) struct sftp_statvfs *st, int quiet)
{ {
struct sshbuf *msg; struct sshbuf *msg;
@ -1484,7 +1486,7 @@ do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
#endif #endif
int int
do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a) sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a)
{ {
struct sshbuf *msg; struct sshbuf *msg;
u_int status, id; u_int status, id;
@ -1592,7 +1594,7 @@ progress_meter_path(const char *path)
} }
int int
do_download(struct sftp_conn *conn, const char *remote_path, sftp_download(struct sftp_conn *conn, const char *remote_path,
const char *local_path, Attrib *a, int preserve_flag, int resume_flag, const char *local_path, Attrib *a, int preserve_flag, int resume_flag,
int fsync_flag, int inplace_flag) int fsync_flag, int inplace_flag)
{ {
@ -1608,14 +1610,18 @@ do_download(struct sftp_conn *conn, const char *remote_path,
struct requests requests; struct requests requests;
struct request *req; struct request *req;
u_char type; u_char type;
Attrib attr;
debug2_f("download remote \"%s\" to local \"%s\"", debug2_f("download remote \"%s\" to local \"%s\"",
remote_path, local_path); remote_path, local_path);
TAILQ_INIT(&requests); TAILQ_INIT(&requests);
if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) if (a == NULL) {
if (sftp_stat(conn, remote_path, 0, &attr) != 0)
return -1; return -1;
a = &attr;
}
/* Do not preserve set[ug]id here, as we do not preserve ownership */ /* Do not preserve set[ug]id here, as we do not preserve ownership */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
@ -1661,7 +1667,7 @@ do_download(struct sftp_conn *conn, const char *remote_path,
error("Unable to resume download of \"%s\": " error("Unable to resume download of \"%s\": "
"local file is larger than remote", local_path); "local file is larger than remote", local_path);
fail: fail:
do_close(conn, handle, handle_len); sftp_close(conn, handle, handle_len);
free(handle); free(handle);
if (local_fd != -1) if (local_fd != -1)
close(local_fd); close(local_fd);
@ -1836,14 +1842,14 @@ do_download(struct sftp_conn *conn, const char *remote_path,
if (read_error) { if (read_error) {
error("read remote \"%s\" : %s", remote_path, fx2txt(status)); error("read remote \"%s\" : %s", remote_path, fx2txt(status));
status = -1; status = -1;
do_close(conn, handle, handle_len); sftp_close(conn, handle, handle_len);
} else if (write_error) { } else if (write_error) {
error("write local \"%s\": %s", local_path, error("write local \"%s\": %s", local_path,
strerror(write_errno)); strerror(write_errno));
status = SSH2_FX_FAILURE; status = SSH2_FX_FAILURE;
do_close(conn, handle, handle_len); sftp_close(conn, handle, handle_len);
} else { } else {
if (do_close(conn, handle, handle_len) != 0 || interrupted) if (sftp_close(conn, handle, handle_len) != 0 || interrupted)
status = SSH2_FX_FAILURE; status = SSH2_FX_FAILURE;
else else
status = SSH2_FX_OK; status = SSH2_FX_OK;
@ -1900,12 +1906,10 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst); debug2_f("download dir remote \"%s\" to local \"%s\"", src, dst);
if (dirattrib == NULL) { if (dirattrib == NULL) {
if ((a = do_stat(conn, src, 1)) == NULL) { if (sftp_stat(conn, src, 1, &ldirattrib) != 0) {
error("stat remote \"%s\" directory failed", src); error("stat remote \"%s\" directory failed", src);
return -1; return -1;
} }
/* Don't let this be clobbered by later do_stat calls */
ldirattrib = *a;
dirattrib = &ldirattrib; dirattrib = &ldirattrib;
} }
if (!S_ISDIR(dirattrib->perm)) { if (!S_ISDIR(dirattrib->perm)) {
@ -1928,7 +1932,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
return -1; return -1;
} }
if (do_readdir(conn, src, &dir_entries) == -1) { if (sftp_readdir(conn, src, &dir_entries) == -1) {
error("remote readdir \"%s\" failed", src); error("remote readdir \"%s\" failed", src);
return -1; return -1;
} }
@ -1938,8 +1942,8 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
free(new_src); free(new_src);
filename = dir_entries[i]->filename; filename = dir_entries[i]->filename;
new_dst = path_append(dst, filename); new_dst = sftp_path_append(dst, filename);
new_src = path_append(src, filename); new_src = sftp_path_append(src, filename);
a = &dir_entries[i]->a; a = &dir_entries[i]->a;
if (S_ISLNK(a->perm)) { if (S_ISLNK(a->perm)) {
@ -1949,13 +1953,11 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
continue; continue;
} }
/* Replace the stat contents with the symlink target */ /* Replace the stat contents with the symlink target */
if ((a = do_stat(conn, new_src, 1)) == NULL) { if (sftp_stat(conn, new_src, 1, &lsym) != 0) {
logit("remote stat \"%s\" failed", new_src); logit("remote stat \"%s\" failed", new_src);
ret = -1; ret = -1;
continue; continue;
} }
/* Don't let this be clobbered by later do_stat calls */
lsym = *a;
a = &lsym; a = &lsym;
} }
@ -1969,7 +1971,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
fsync_flag, follow_link_flag, inplace_flag) == -1) fsync_flag, follow_link_flag, inplace_flag) == -1)
ret = -1; ret = -1;
} else if (S_ISREG(a->perm)) { } else if (S_ISREG(a->perm)) {
if (do_download(conn, new_src, new_dst, a, if (sftp_download(conn, new_src, new_dst, a,
preserve_flag, resume_flag, fsync_flag, preserve_flag, resume_flag, fsync_flag,
inplace_flag) == -1) { inplace_flag) == -1) {
error("Download of file %s to %s failed", error("Download of file %s to %s failed",
@ -2001,20 +2003,20 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
error("local chmod directory \"%s\": %s", dst, error("local chmod directory \"%s\": %s", dst,
strerror(errno)); strerror(errno));
free_sftp_dirents(dir_entries); sftp_free_dirents(dir_entries);
return ret; return ret;
} }
int int
download_dir(struct sftp_conn *conn, const char *src, const char *dst, sftp_download_dir(struct sftp_conn *conn, const char *src, const char *dst,
Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag, Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
int fsync_flag, int follow_link_flag, int inplace_flag) int fsync_flag, int follow_link_flag, int inplace_flag)
{ {
char *src_canon; char *src_canon;
int ret; int ret;
if ((src_canon = do_realpath(conn, src)) == NULL) { if ((src_canon = sftp_realpath(conn, src)) == NULL) {
error("download \"%s\": path canonicalization failed", src); error("download \"%s\": path canonicalization failed", src);
return -1; return -1;
} }
@ -2027,7 +2029,7 @@ download_dir(struct sftp_conn *conn, const char *src, const char *dst,
} }
int int
do_upload(struct sftp_conn *conn, const char *local_path, sftp_upload(struct sftp_conn *conn, const char *local_path,
const char *remote_path, int preserve_flag, int resume, const char *remote_path, int preserve_flag, int resume,
int fsync_flag, int inplace_flag) int fsync_flag, int inplace_flag)
{ {
@ -2037,7 +2039,7 @@ do_upload(struct sftp_conn *conn, const char *local_path,
u_char type, *handle, *data; u_char type, *handle, *data;
struct sshbuf *msg; struct sshbuf *msg;
struct stat sb; struct stat sb;
Attrib a, t, *c = NULL; Attrib a, t, c;
u_int32_t startid, ackid; u_int32_t startid, ackid;
u_int64_t highwater = 0, maxack = 0; u_int64_t highwater = 0, maxack = 0;
struct request *ack = NULL; struct request *ack = NULL;
@ -2073,19 +2075,19 @@ do_upload(struct sftp_conn *conn, const char *local_path,
if (resume) { if (resume) {
/* Get remote file size if it exists */ /* Get remote file size if it exists */
if ((c = do_stat(conn, remote_path, 0)) == NULL) { if (sftp_stat(conn, remote_path, 0, &c) != 0) {
close(local_fd); close(local_fd);
return -1; return -1;
} }
if ((off_t)c->size >= sb.st_size) { if ((off_t)c.size >= sb.st_size) {
error("resume \"%s\": destination file " error("resume \"%s\": destination file "
"same size or larger", local_path); "same size or larger", local_path);
close(local_fd); close(local_fd);
return -1; return -1;
} }
if (lseek(local_fd, (off_t)c->size, SEEK_SET) == -1) { if (lseek(local_fd, (off_t)c.size, SEEK_SET) == -1) {
close(local_fd); close(local_fd);
return -1; return -1;
} }
@ -2109,7 +2111,7 @@ do_upload(struct sftp_conn *conn, const char *local_path,
data = xmalloc(conn->upload_buflen); data = xmalloc(conn->upload_buflen);
/* Read from local and write to remote */ /* Read from local and write to remote */
offset = progress_counter = (resume ? c->size : 0); offset = progress_counter = (resume ? c.size : 0);
if (showprogress) { if (showprogress) {
start_progress_meter(progress_meter_path(local_path), start_progress_meter(progress_meter_path(local_path),
sb.st_size, &progress_counter); sb.st_size, &progress_counter);
@ -2221,7 +2223,7 @@ do_upload(struct sftp_conn *conn, const char *local_path,
attrib_clear(&t); attrib_clear(&t);
t.flags = SSH2_FILEXFER_ATTR_SIZE; t.flags = SSH2_FILEXFER_ATTR_SIZE;
t.size = highwater; t.size = highwater;
do_fsetstat(conn, handle, handle_len, &t); sftp_fsetstat(conn, handle, handle_len, &t);
} }
if (close(local_fd) == -1) { if (close(local_fd) == -1) {
@ -2231,12 +2233,12 @@ do_upload(struct sftp_conn *conn, const char *local_path,
/* Override umask and utimes if asked */ /* Override umask and utimes if asked */
if (preserve_flag) if (preserve_flag)
do_fsetstat(conn, handle, handle_len, &a); sftp_fsetstat(conn, handle, handle_len, &a);
if (fsync_flag) if (fsync_flag)
(void)do_fsync(conn, handle, handle_len); (void)sftp_fsync(conn, handle, handle_len);
if (do_close(conn, handle, handle_len) != 0) if (sftp_close(conn, handle, handle_len) != 0)
status = SSH2_FX_FAILURE; status = SSH2_FX_FAILURE;
free(handle); free(handle);
@ -2254,7 +2256,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
struct dirent *dp; struct dirent *dp;
char *filename, *new_src = NULL, *new_dst = NULL; char *filename, *new_src = NULL, *new_dst = NULL;
struct stat sb; struct stat sb;
Attrib a, *dirattrib; Attrib a, dirattrib;
u_int32_t saved_perm; u_int32_t saved_perm;
debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst); debug2_f("upload local dir \"%s\" to remote \"%s\"", src, dst);
@ -2290,10 +2292,10 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
*/ */
saved_perm = a.perm; saved_perm = a.perm;
a.perm |= (S_IWUSR|S_IXUSR); a.perm |= (S_IWUSR|S_IXUSR);
if (do_mkdir(conn, dst, &a, 0) != 0) { if (sftp_mkdir(conn, dst, &a, 0) != 0) {
if ((dirattrib = do_stat(conn, dst, 0)) == NULL) if (sftp_stat(conn, dst, 0, &dirattrib) != 0)
return -1; return -1;
if (!S_ISDIR(dirattrib->perm)) { if (!S_ISDIR(dirattrib.perm)) {
error("\"%s\" exists but is not a directory", dst); error("\"%s\" exists but is not a directory", dst);
return -1; return -1;
} }
@ -2311,8 +2313,8 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
free(new_dst); free(new_dst);
free(new_src); free(new_src);
filename = dp->d_name; filename = dp->d_name;
new_dst = path_append(dst, filename); new_dst = sftp_path_append(dst, filename);
new_src = path_append(src, filename); new_src = sftp_path_append(src, filename);
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
continue; continue;
@ -2341,7 +2343,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
fsync_flag, follow_link_flag, inplace_flag) == -1) fsync_flag, follow_link_flag, inplace_flag) == -1)
ret = -1; ret = -1;
} else if (S_ISREG(sb.st_mode)) { } else if (S_ISREG(sb.st_mode)) {
if (do_upload(conn, new_src, new_dst, if (sftp_upload(conn, new_src, new_dst,
preserve_flag, resume, fsync_flag, preserve_flag, resume, fsync_flag,
inplace_flag) == -1) { inplace_flag) == -1) {
error("upload \"%s\" to \"%s\" failed", error("upload \"%s\" to \"%s\" failed",
@ -2354,21 +2356,21 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
free(new_dst); free(new_dst);
free(new_src); free(new_src);
do_setstat(conn, dst, &a); sftp_setstat(conn, dst, &a);
(void) closedir(dirp); (void) closedir(dirp);
return ret; return ret;
} }
int int
upload_dir(struct sftp_conn *conn, const char *src, const char *dst, sftp_upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
int preserve_flag, int print_flag, int resume, int fsync_flag, int preserve_flag, int print_flag, int resume, int fsync_flag,
int follow_link_flag, int inplace_flag) int follow_link_flag, int inplace_flag)
{ {
char *dst_canon; char *dst_canon;
int ret; int ret;
if ((dst_canon = do_realpath(conn, dst)) == NULL) { if ((dst_canon = sftp_realpath(conn, dst)) == NULL) {
error("upload \"%s\": path canonicalization failed", dst); error("upload \"%s\": path canonicalization failed", dst);
return -1; return -1;
} }
@ -2427,13 +2429,13 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous,
*write_errorp = status; *write_errorp = status;
} }
/* /*
* XXX this doesn't do full reply matching like do_upload and * XXX this doesn't do full reply matching like sftp_upload and
* so cannot gracefully truncate terminated uploads at a * so cannot gracefully truncate terminated uploads at a
* high-water mark. ATM the only caller of this function (scp) * high-water mark. ATM the only caller of this function (scp)
* doesn't support transfer resumption, so this doesn't matter * doesn't support transfer resumption, so this doesn't matter
* a whole lot. * a whole lot.
* *
* To be safe, do_crossload truncates the destination file to * To be safe, sftp_crossload truncates the destination file to
* zero length on upload failure, since we can't trust the * zero length on upload failure, since we can't trust the
* server not to have reordered replies that could have * server not to have reordered replies that could have
* inserted holes where none existed in the source file. * inserted holes where none existed in the source file.
@ -2448,7 +2450,7 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous,
} }
int int
do_crossload(struct sftp_conn *from, struct sftp_conn *to, sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path, const char *from_path, const char *to_path,
Attrib *a, int preserve_flag) Attrib *a, int preserve_flag)
{ {
@ -2463,13 +2465,17 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
struct requests requests; struct requests requests;
struct request *req; struct request *req;
u_char type; u_char type;
Attrib attr;
debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path); debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path);
TAILQ_INIT(&requests); TAILQ_INIT(&requests);
if (a == NULL && (a = do_stat(from, from_path, 0)) == NULL) if (a == NULL) {
if (sftp_stat(from, from_path, 0, &attr) != 0)
return -1; return -1;
a = &attr;
}
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(!S_ISREG(a->perm))) { (!S_ISREG(a->perm))) {
@ -2499,7 +2505,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
if (send_open(to, to_path, "dest", if (send_open(to, to_path, "dest",
SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
&to_handle, &to_handle_len) != 0) { &to_handle, &to_handle_len) != 0) {
do_close(from, from_handle, from_handle_len); sftp_close(from, from_handle, from_handle_len);
return -1; return -1;
} }
@ -2649,7 +2655,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
/* Truncate at 0 length on interrupt or error to avoid holes at dest */ /* Truncate at 0 length on interrupt or error to avoid holes at dest */
if (read_error || write_error || interrupted) { if (read_error || write_error || interrupted) {
debug("truncating \"%s\" at 0", to_path); debug("truncating \"%s\" at 0", to_path);
do_close(to, to_handle, to_handle_len); sftp_close(to, to_handle, to_handle_len);
free(to_handle); free(to_handle);
if (send_open(to, to_path, "dest", if (send_open(to, to_path, "dest",
SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
@ -2661,17 +2667,17 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
if (read_error) { if (read_error) {
error("read origin \"%s\": %s", from_path, fx2txt(status)); error("read origin \"%s\": %s", from_path, fx2txt(status));
status = -1; status = -1;
do_close(from, from_handle, from_handle_len); sftp_close(from, from_handle, from_handle_len);
if (to_handle != NULL) if (to_handle != NULL)
do_close(to, to_handle, to_handle_len); sftp_close(to, to_handle, to_handle_len);
} else if (write_error) { } else if (write_error) {
error("write dest \"%s\": %s", to_path, fx2txt(write_error)); error("write dest \"%s\": %s", to_path, fx2txt(write_error));
status = SSH2_FX_FAILURE; status = SSH2_FX_FAILURE;
do_close(from, from_handle, from_handle_len); sftp_close(from, from_handle, from_handle_len);
if (to_handle != NULL) if (to_handle != NULL)
do_close(to, to_handle, to_handle_len); sftp_close(to, to_handle, to_handle_len);
} else { } else {
if (do_close(from, from_handle, from_handle_len) != 0 || if (sftp_close(from, from_handle, from_handle_len) != 0 ||
interrupted) interrupted)
status = -1; status = -1;
else else
@ -2679,8 +2685,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
if (to_handle != NULL) { if (to_handle != NULL) {
/* Need to resend utimes after write */ /* Need to resend utimes after write */
if (preserve_flag) if (preserve_flag)
do_fsetstat(to, to_handle, to_handle_len, a); sftp_fsetstat(to, to_handle, to_handle_len, a);
do_close(to, to_handle, to_handle_len); sftp_close(to, to_handle, to_handle_len);
} }
} }
sshbuf_free(msg); sshbuf_free(msg);
@ -2700,7 +2706,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
SFTP_DIRENT **dir_entries; SFTP_DIRENT **dir_entries;
char *filename, *new_from_path = NULL, *new_to_path = NULL; char *filename, *new_from_path = NULL, *new_to_path = NULL;
mode_t mode = 0777; mode_t mode = 0777;
Attrib curdir; Attrib curdir, ldirattrib, newdir;
debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path); debug2_f("crossload dir src \"%s\" to dst \"%s\"", from_path, to_path);
@ -2709,11 +2715,13 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
return -1; return -1;
} }
if (dirattrib == NULL && if (dirattrib == NULL) {
(dirattrib = do_stat(from, from_path, 1)) == NULL) { if (sftp_stat(from, from_path, 1, &ldirattrib) != 0) {
error("stat remote \"%s\" failed", from_path); error("stat remote \"%s\" failed", from_path);
return -1; return -1;
} }
dirattrib = &ldirattrib;
}
if (!S_ISDIR(dirattrib->perm)) { if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" is not a directory", from_path); error("\"%s\" is not a directory", from_path);
return -1; return -1;
@ -2740,17 +2748,17 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
* the path already existed and is a directory. Ensure we can * the path already existed and is a directory. Ensure we can
* write to the directory we create for the duration of the transfer. * write to the directory we create for the duration of the transfer.
*/ */
if (do_mkdir(to, to_path, &curdir, 0) != 0) { if (sftp_mkdir(to, to_path, &curdir, 0) != 0) {
if ((dirattrib = do_stat(to, to_path, 0)) == NULL) if (sftp_stat(to, to_path, 0, &newdir) != 0)
return -1; return -1;
if (!S_ISDIR(dirattrib->perm)) { if (!S_ISDIR(newdir.perm)) {
error("\"%s\" exists but is not a directory", to_path); error("\"%s\" exists but is not a directory", to_path);
return -1; return -1;
} }
} }
curdir.perm = mode; curdir.perm = mode;
if (do_readdir(from, from_path, &dir_entries) == -1) { if (sftp_readdir(from, from_path, &dir_entries) == -1) {
error("origin readdir \"%s\" failed", from_path); error("origin readdir \"%s\" failed", from_path);
return -1; return -1;
} }
@ -2760,8 +2768,8 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
free(new_to_path); free(new_to_path);
filename = dir_entries[i]->filename; filename = dir_entries[i]->filename;
new_from_path = path_append(from_path, filename); new_from_path = sftp_path_append(from_path, filename);
new_to_path = path_append(to_path, filename); new_to_path = sftp_path_append(to_path, filename);
if (S_ISDIR(dir_entries[i]->a.perm)) { if (S_ISDIR(dir_entries[i]->a.perm)) {
if (strcmp(filename, ".") == 0 || if (strcmp(filename, ".") == 0 ||
@ -2776,10 +2784,10 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
(follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) { (follow_link_flag && S_ISLNK(dir_entries[i]->a.perm))) {
/* /*
* If this is a symlink then don't send the link's * If this is a symlink then don't send the link's
* Attrib. do_download() will do a FXP_STAT operation * Attrib. sftp_download() will do a FXP_STAT operation
* and get the link target's attributes. * and get the link target's attributes.
*/ */
if (do_crossload(from, to, new_from_path, new_to_path, if (sftp_crossload(from, to, new_from_path, new_to_path,
S_ISLNK(dir_entries[i]->a.perm) ? NULL : S_ISLNK(dir_entries[i]->a.perm) ? NULL :
&(dir_entries[i]->a), preserve_flag) == -1) { &(dir_entries[i]->a), preserve_flag) == -1) {
error("crossload \"%s\" to \"%s\" failed", error("crossload \"%s\" to \"%s\" failed",
@ -2794,22 +2802,22 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
free(new_to_path); free(new_to_path);
free(new_from_path); free(new_from_path);
do_setstat(to, to_path, &curdir); sftp_setstat(to, to_path, &curdir);
free_sftp_dirents(dir_entries); sftp_free_dirents(dir_entries);
return ret; return ret;
} }
int int
crossload_dir(struct sftp_conn *from, struct sftp_conn *to, sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path, const char *from_path, const char *to_path,
Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag) Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)
{ {
char *from_path_canon; char *from_path_canon;
int ret; int ret;
if ((from_path_canon = do_realpath(from, from_path)) == NULL) { if ((from_path_canon = sftp_realpath(from, from_path)) == NULL) {
error("crossload \"%s\": path canonicalization failed", error("crossload \"%s\": path canonicalization failed",
from_path); from_path);
return -1; return -1;
@ -2822,13 +2830,13 @@ crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
} }
int int
can_get_users_groups_by_id(struct sftp_conn *conn) sftp_can_get_users_groups_by_id(struct sftp_conn *conn)
{ {
return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0; return (conn->exts & SFTP_EXT_GETUSERSGROUPS_BY_ID) != 0;
} }
int int
do_get_users_groups_by_id(struct sftp_conn *conn, sftp_get_users_groups_by_id(struct sftp_conn *conn,
const u_int *uids, u_int nuids, const u_int *uids, u_int nuids,
const u_int *gids, u_int ngids, const u_int *gids, u_int ngids,
char ***usernamesp, char ***groupnamesp) char ***usernamesp, char ***groupnamesp)
@ -2840,7 +2848,7 @@ do_get_users_groups_by_id(struct sftp_conn *conn,
int r; int r;
*usernamesp = *groupnamesp = NULL; *usernamesp = *groupnamesp = NULL;
if (!can_get_users_groups_by_id(conn)) if (!sftp_can_get_users_groups_by_id(conn))
return SSH_ERR_FEATURE_UNSUPPORTED; return SSH_ERR_FEATURE_UNSUPPORTED;
if ((msg = sshbuf_new()) == NULL || if ((msg = sshbuf_new()) == NULL ||
@ -2936,7 +2944,7 @@ do_get_users_groups_by_id(struct sftp_conn *conn,
} }
char * char *
path_append(const char *p1, const char *p2) sftp_path_append(const char *p1, const char *p2)
{ {
char *ret; char *ret;
size_t len = strlen(p1) + strlen(p2) + 2; size_t len = strlen(p1) + strlen(p2) + 2;
@ -2955,13 +2963,13 @@ path_append(const char *p1, const char *p2)
* freed and a replacement allocated. Caller must free returned string. * freed and a replacement allocated. Caller must free returned string.
*/ */
char * char *
make_absolute(char *p, const char *pwd) sftp_make_absolute(char *p, const char *pwd)
{ {
char *abs_str; char *abs_str;
/* Derelativise */ /* Derelativise */
if (p && !path_absolute(p)) { if (p && !path_absolute(p)) {
abs_str = path_append(pwd, p); abs_str = sftp_path_append(pwd, p);
free(p); free(p);
return(abs_str); return(abs_str);
} else } else
@ -2969,34 +2977,22 @@ make_absolute(char *p, const char *pwd)
} }
int int
remote_is_dir(struct sftp_conn *conn, const char *path) sftp_remote_is_dir(struct sftp_conn *conn, const char *path)
{ {
Attrib *a; Attrib a;
/* XXX: report errors? */ /* XXX: report errors? */
if ((a = do_stat(conn, path, 1)) == NULL) if (sftp_stat(conn, path, 1, &a) != 0)
return(0); return(0);
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) if (!(a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
return(0); return(0);
return(S_ISDIR(a->perm)); return S_ISDIR(a.perm);
} }
int
local_is_dir(const char *path)
{
struct stat sb;
/* XXX: report errors? */
if (stat(path, &sb) == -1)
return(0);
return(S_ISDIR(sb.st_mode));
}
/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
int int
globpath_is_dir(const char *pathname) sftp_globpath_is_dir(const char *pathname)
{ {
size_t l = strlen(pathname); size_t l = strlen(pathname);

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-client.h,v 1.38 2022/09/19 10:43:12 djm Exp $ */ /* $OpenBSD: sftp-client.h,v 1.39 2023/09/08 05:56:13 djm Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
@ -70,107 +70,106 @@ struct sftp_limits {
* Initialise a SSH filexfer connection. Returns NULL on error or * Initialise a SSH filexfer connection. Returns NULL on error or
* a pointer to a initialized sftp_conn struct on success. * a pointer to a initialized sftp_conn struct on success.
*/ */
struct sftp_conn *do_init(int, int, u_int, u_int, u_int64_t); struct sftp_conn *sftp_init(int, int, u_int, u_int, u_int64_t);
u_int sftp_proto_version(struct sftp_conn *); u_int sftp_proto_version(struct sftp_conn *);
/* Query server limits */ /* Query server limits */
int do_limits(struct sftp_conn *, struct sftp_limits *); int sftp_get_limits(struct sftp_conn *, struct sftp_limits *);
/* Close file referred to by 'handle' */ /* Close file referred to by 'handle' */
int do_close(struct sftp_conn *, const u_char *, u_int); int sftp_close(struct sftp_conn *, const u_char *, u_int);
/* Read contents of 'path' to NULL-terminated array 'dir' */ /* Read contents of 'path' to NULL-terminated array 'dir' */
int do_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***); int sftp_readdir(struct sftp_conn *, const char *, SFTP_DIRENT ***);
/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from do_readdir) */ /* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from sftp_readdir) */
void free_sftp_dirents(SFTP_DIRENT **); void sftp_free_dirents(SFTP_DIRENT **);
/* Delete file 'path' */ /* Delete file 'path' */
int do_rm(struct sftp_conn *, const char *); int sftp_rm(struct sftp_conn *, const char *);
/* Create directory 'path' */ /* Create directory 'path' */
int do_mkdir(struct sftp_conn *, const char *, Attrib *, int); int sftp_mkdir(struct sftp_conn *, const char *, Attrib *, int);
/* Remove directory 'path' */ /* Remove directory 'path' */
int do_rmdir(struct sftp_conn *, const char *); int sftp_rmdir(struct sftp_conn *, const char *);
/* Get file attributes of 'path' (follows symlinks) */ /* Get file attributes of 'path' (follows symlinks) */
Attrib *do_stat(struct sftp_conn *, const char *, int); int sftp_stat(struct sftp_conn *, const char *, int, Attrib *);
/* Get file attributes of 'path' (does not follow symlinks) */ /* Get file attributes of 'path' (does not follow symlinks) */
Attrib *do_lstat(struct sftp_conn *, const char *, int); int sftp_lstat(struct sftp_conn *, const char *, int, Attrib *);
/* Set file attributes of 'path' */ /* Set file attributes of 'path' */
int do_setstat(struct sftp_conn *, const char *, Attrib *); int sftp_setstat(struct sftp_conn *, const char *, Attrib *);
/* Set file attributes of open file 'handle' */ /* Set file attributes of open file 'handle' */
int do_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *); int sftp_fsetstat(struct sftp_conn *, const u_char *, u_int, Attrib *);
/* Set file attributes of 'path', not following symlinks */ /* Set file attributes of 'path', not following symlinks */
int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a); int sftp_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
/* Canonicalise 'path' - caller must free result */ /* Canonicalise 'path' - caller must free result */
char *do_realpath(struct sftp_conn *, const char *); char *sftp_realpath(struct sftp_conn *, const char *);
/* Canonicalisation with tilde expansion (requires server extension) */ /* Canonicalisation with tilde expansion (requires server extension) */
char *do_expand_path(struct sftp_conn *, const char *); char *sftp_expand_path(struct sftp_conn *, const char *);
/* Returns non-zero if server can tilde-expand paths */ /* Returns non-zero if server can tilde-expand paths */
int can_expand_path(struct sftp_conn *); int sftp_can_expand_path(struct sftp_conn *);
/* Get statistics for filesystem hosting file at "path" */ /* Get statistics for filesystem hosting file at "path" */
int do_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int); int sftp_statvfs(struct sftp_conn *, const char *, struct sftp_statvfs *, int);
/* Rename 'oldpath' to 'newpath' */ /* Rename 'oldpath' to 'newpath' */
int do_rename(struct sftp_conn *, const char *, const char *, int); int sftp_rename(struct sftp_conn *, const char *, const char *, int);
/* Copy 'oldpath' to 'newpath' */ /* Copy 'oldpath' to 'newpath' */
int do_copy(struct sftp_conn *, const char *, const char *); int sftp_copy(struct sftp_conn *, const char *, const char *);
/* Link 'oldpath' to 'newpath' */ /* Link 'oldpath' to 'newpath' */
int do_hardlink(struct sftp_conn *, const char *, const char *); int sftp_hardlink(struct sftp_conn *, const char *, const char *);
/* Rename 'oldpath' to 'newpath' */ /* Rename 'oldpath' to 'newpath' */
int do_symlink(struct sftp_conn *, const char *, const char *); int sftp_symlink(struct sftp_conn *, const char *, const char *);
/* Call fsync() on open file 'handle' */ /* Call fsync() on open file 'handle' */
int do_fsync(struct sftp_conn *conn, u_char *, u_int); int sftp_fsync(struct sftp_conn *conn, u_char *, u_int);
/* /*
* Download 'remote_path' to 'local_path'. Preserve permissions and times * Download 'remote_path' to 'local_path'. Preserve permissions and times
* if 'pflag' is set * if 'pflag' is set
*/ */
int do_download(struct sftp_conn *, const char *, const char *, Attrib *, int sftp_download(struct sftp_conn *, const char *, const char *, Attrib *,
int, int, int, int); int, int, int, int);
/* /*
* Recursively download 'remote_directory' to 'local_directory'. Preserve * Recursively download 'remote_directory' to 'local_directory'. Preserve
* times if 'pflag' is set * times if 'pflag' is set
*/ */
int download_dir(struct sftp_conn *, const char *, const char *, Attrib *, int sftp_download_dir(struct sftp_conn *, const char *, const char *, Attrib *,
int, int, int, int, int, int); int, int, int, int, int, int);
/* /*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times * Upload 'local_path' to 'remote_path'. Preserve permissions and times
* if 'pflag' is set * if 'pflag' is set
*/ */
int do_upload(struct sftp_conn *, const char *, const char *, int sftp_upload(struct sftp_conn *, const char *, const char *,
int, int, int, int); int, int, int, int);
/* /*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve * Recursively upload 'local_directory' to 'remote_directory'. Preserve
* times if 'pflag' is set * times if 'pflag' is set
*/ */
int upload_dir(struct sftp_conn *, const char *, const char *, int sftp_upload_dir(struct sftp_conn *, const char *, const char *,
int, int, int, int, int, int); int, int, int, int, int, int);
/* /*
* Download a 'from_path' from the 'from' connection and upload it to * Download a 'from_path' from the 'from' connection and upload it to
* to 'to' connection at 'to_path'. * to 'to' connection at 'to_path'.
*/ */
int int sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
do_crossload(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path, const char *from_path, const char *to_path,
Attrib *a, int preserve_flag); Attrib *a, int preserve_flag);
@ -178,7 +177,7 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
* Recursively download a directory from 'from_path' from the 'from' * Recursively download a directory from 'from_path' from the 'from'
* connection and upload it to 'to' connection at 'to_path'. * connection and upload it to 'to' connection at 'to_path'.
*/ */
int crossload_dir(struct sftp_conn *from, struct sftp_conn *to, int sftp_crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path, const char *from_path, const char *to_path,
Attrib *dirattrib, int preserve_flag, int print_flag, Attrib *dirattrib, int preserve_flag, int print_flag,
int follow_link_flag); int follow_link_flag);
@ -186,26 +185,23 @@ int crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
/* /*
* User/group ID to name translation. * User/group ID to name translation.
*/ */
int can_get_users_groups_by_id(struct sftp_conn *conn); int sftp_can_get_users_groups_by_id(struct sftp_conn *conn);
int do_get_users_groups_by_id(struct sftp_conn *conn, int sftp_get_users_groups_by_id(struct sftp_conn *conn,
const u_int *uids, u_int nuids, const u_int *uids, u_int nuids,
const u_int *gids, u_int ngids, const u_int *gids, u_int ngids,
char ***usernamesp, char ***groupnamesp); char ***usernamesp, char ***groupnamesp);
/* Concatenate paths, taking care of slashes. Caller must free result. */ /* Concatenate paths, taking care of slashes. Caller must free result. */
char *path_append(const char *, const char *); char *sftp_path_append(const char *, const char *);
/* Make absolute path if relative path and CWD is given. Does not modify /* Make absolute path if relative path and CWD is given. Does not modify
* original if the path is already absolute. */ * original if the path is already absolute. */
char *make_absolute(char *, const char *); char *sftp_make_absolute(char *, const char *);
/* Check if remote path is directory */ /* Check if remote path is directory */
int remote_is_dir(struct sftp_conn *conn, const char *path); int sftp_remote_is_dir(struct sftp_conn *conn, const char *path);
/* Check if local path is directory */
int local_is_dir(const char *path);
/* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */ /* Check whether path returned from glob(..., GLOB_MARK, ...) is a directory */
int globpath_is_dir(const char *pathname); int sftp_globpath_is_dir(const char *pathname);
#endif #endif

View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp-glob.c,v 1.31 2022/10/24 21:51:55 djm Exp $ */ /* $OpenBSD: sftp-glob.c,v 1.32 2023/09/08 05:56:13 djm Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
* *
@ -51,7 +51,7 @@ fudge_opendir(const char *path)
r = xcalloc(1, sizeof(*r)); r = xcalloc(1, sizeof(*r));
if (do_readdir(cur.conn, path, &r->dir)) { if (sftp_readdir(cur.conn, path, &r->dir)) {
free(r); free(r);
return(NULL); return(NULL);
} }
@ -103,32 +103,32 @@ fudge_readdir(struct SFTP_OPENDIR *od)
static void static void
fudge_closedir(struct SFTP_OPENDIR *od) fudge_closedir(struct SFTP_OPENDIR *od)
{ {
free_sftp_dirents(od->dir); sftp_free_dirents(od->dir);
free(od); free(od);
} }
static int static int
fudge_lstat(const char *path, struct stat *st) fudge_lstat(const char *path, struct stat *st)
{ {
Attrib *a; Attrib a;
if (!(a = do_lstat(cur.conn, path, 1))) if (sftp_lstat(cur.conn, path, 1, &a) != 0)
return(-1); return -1;
attrib_to_stat(a, st); attrib_to_stat(&a, st);
return(0); return 0;
} }
static int static int
fudge_stat(const char *path, struct stat *st) fudge_stat(const char *path, struct stat *st)
{ {
Attrib *a; Attrib a;
if (!(a = do_stat(cur.conn, path, 1))) if (sftp_stat(cur.conn, path, 1, &a) != 0)
return(-1); return -1;
attrib_to_stat(a, st); attrib_to_stat(&a, st);
return(0); return(0);
} }

View File

@ -106,9 +106,9 @@ lookup_and_record(struct sftp_conn *conn,
u_int i; u_int i;
char **usernames = NULL, **groupnames = NULL; char **usernames = NULL, **groupnames = NULL;
if ((r = do_get_users_groups_by_id(conn, uids, nuids, gids, ngids, if ((r = sftp_get_users_groups_by_id(conn, uids, nuids, gids, ngids,
&usernames, &groupnames)) != 0) { &usernames, &groupnames)) != 0) {
debug_fr(r, "do_get_users_groups_by_id"); debug_fr(r, "sftp_get_users_groups_by_id");
return; return;
} }
for (i = 0; i < nuids; i++) { for (i = 0; i < nuids; i++) {
@ -176,7 +176,7 @@ get_remote_user_groups_from_glob(struct sftp_conn *conn, glob_t *g)
{ {
u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0; u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
if (!can_get_users_groups_by_id(conn)) if (!sftp_can_get_users_groups_by_id(conn))
return; return;
collect_ids_from_glob(g, 1, &uids, &nuids); collect_ids_from_glob(g, 1, &uids, &nuids);
@ -215,7 +215,7 @@ get_remote_user_groups_from_dirents(struct sftp_conn *conn, SFTP_DIRENT **d)
{ {
u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0; u_int *uids = NULL, nuids = 0, *gids = NULL, ngids = 0;
if (!can_get_users_groups_by_id(conn)) if (!sftp_can_get_users_groups_by_id(conn))
return; return;
collect_ids_from_dirents(d, 1, &uids, &nuids); collect_ids_from_dirents(d, 1, &uids, &nuids);

124
sftp.c
View File

@ -1,4 +1,4 @@
/* $OpenBSD: sftp.c,v 1.234 2023/04/12 08:53:54 jsg Exp $ */ /* $OpenBSD: sftp.c,v 1.235 2023/09/08 05:56:13 djm Exp $ */
/* /*
* Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
* *
@ -628,11 +628,21 @@ make_absolute_pwd_glob(char *p, const char *pwd)
escpwd = escape_glob(pwd); escpwd = escape_glob(pwd);
if (p == NULL) if (p == NULL)
return escpwd; return escpwd;
ret = make_absolute(p, escpwd); ret = sftp_make_absolute(p, escpwd);
free(escpwd); free(escpwd);
return ret; return ret;
} }
static int
local_is_dir(const char *path)
{
struct stat sb;
if (stat(path, &sb) == -1)
return 0;
return S_ISDIR(sb.st_mode);
}
static int static int
process_get(struct sftp_conn *conn, const char *src, const char *dst, process_get(struct sftp_conn *conn, const char *src, const char *dst,
const char *pwd, int pflag, int rflag, int resume, int fflag) const char *pwd, int pflag, int rflag, int resume, int fflag)
@ -677,12 +687,12 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst,
if (g.gl_matchc == 1 && dst) { if (g.gl_matchc == 1 && dst) {
if (local_is_dir(dst)) { if (local_is_dir(dst)) {
abs_dst = path_append(dst, filename); abs_dst = sftp_path_append(dst, filename);
} else { } else {
abs_dst = xstrdup(dst); abs_dst = xstrdup(dst);
} }
} else if (dst) { } else if (dst) {
abs_dst = path_append(dst, filename); abs_dst = sftp_path_append(dst, filename);
} else { } else {
abs_dst = xstrdup(filename); abs_dst = xstrdup(filename);
} }
@ -696,13 +706,14 @@ process_get(struct sftp_conn *conn, const char *src, const char *dst,
mprintf("Fetching %s to %s\n", mprintf("Fetching %s to %s\n",
g.gl_pathv[i], abs_dst); g.gl_pathv[i], abs_dst);
/* XXX follow link flag */ /* XXX follow link flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { if (sftp_globpath_is_dir(g.gl_pathv[i]) &&
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL, (rflag || global_rflag)) {
pflag || global_pflag, 1, resume, if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst,
NULL, pflag || global_pflag, 1, resume,
fflag || global_fflag, 0, 0) == -1) fflag || global_fflag, 0, 0) == -1)
err = -1; err = -1;
} else { } else {
if (do_download(conn, g.gl_pathv[i], abs_dst, NULL, if (sftp_download(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, resume, pflag || global_pflag, resume,
fflag || global_fflag, 0) == -1) fflag || global_fflag, 0) == -1)
err = -1; err = -1;
@ -731,7 +742,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
if (dst) { if (dst) {
tmp_dst = xstrdup(dst); tmp_dst = xstrdup(dst);
tmp_dst = make_absolute(tmp_dst, pwd); tmp_dst = sftp_make_absolute(tmp_dst, pwd);
} }
memset(&g, 0, sizeof(g)); memset(&g, 0, sizeof(g));
@ -744,7 +755,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
/* If we aren't fetching to pwd then stash this status for later */ /* If we aren't fetching to pwd then stash this status for later */
if (tmp_dst != NULL) if (tmp_dst != NULL)
dst_is_dir = remote_is_dir(conn, tmp_dst); dst_is_dir = sftp_remote_is_dir(conn, tmp_dst);
/* If multiple matches, dst may be directory or unspecified */ /* If multiple matches, dst may be directory or unspecified */
if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) { if (g.gl_matchc > 1 && tmp_dst && !dst_is_dir) {
@ -774,13 +785,13 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
if (g.gl_matchc == 1 && tmp_dst) { if (g.gl_matchc == 1 && tmp_dst) {
/* If directory specified, append filename */ /* If directory specified, append filename */
if (dst_is_dir) if (dst_is_dir)
abs_dst = path_append(tmp_dst, filename); abs_dst = sftp_path_append(tmp_dst, filename);
else else
abs_dst = xstrdup(tmp_dst); abs_dst = xstrdup(tmp_dst);
} else if (tmp_dst) { } else if (tmp_dst) {
abs_dst = path_append(tmp_dst, filename); abs_dst = sftp_path_append(tmp_dst, filename);
} else { } else {
abs_dst = make_absolute(xstrdup(filename), pwd); abs_dst = sftp_make_absolute(xstrdup(filename), pwd);
} }
free(tmp); free(tmp);
@ -792,13 +803,14 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
mprintf("Uploading %s to %s\n", mprintf("Uploading %s to %s\n",
g.gl_pathv[i], abs_dst); g.gl_pathv[i], abs_dst);
/* XXX follow_link_flag */ /* XXX follow_link_flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) { if (sftp_globpath_is_dir(g.gl_pathv[i]) &&
if (upload_dir(conn, g.gl_pathv[i], abs_dst, (rflag || global_rflag)) {
if (sftp_upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume, pflag || global_pflag, 1, resume,
fflag || global_fflag, 0, 0) == -1) fflag || global_fflag, 0, 0) == -1)
err = -1; err = -1;
} else { } else {
if (do_upload(conn, g.gl_pathv[i], abs_dst, if (sftp_upload(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, resume, pflag || global_pflag, resume,
fflag || global_fflag, 0) == -1) fflag || global_fflag, 0) == -1)
err = -1; err = -1;
@ -839,7 +851,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
u_int c = 1, colspace = 0, columns = 1; u_int c = 1, colspace = 0, columns = 1;
SFTP_DIRENT **d; SFTP_DIRENT **d;
if ((n = do_readdir(conn, path, &d)) != 0) if ((n = sftp_readdir(conn, path, &d)) != 0)
return (n); return (n);
if (!(lflag & LS_SHORT_VIEW)) { if (!(lflag & LS_SHORT_VIEW)) {
@ -881,13 +893,13 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL)) if (d[n]->filename[0] == '.' && !(lflag & LS_SHOW_ALL))
continue; continue;
tmp = path_append(path, d[n]->filename); tmp = sftp_path_append(path, d[n]->filename);
fname = path_strip(tmp, strip_path); fname = path_strip(tmp, strip_path);
free(tmp); free(tmp);
if (lflag & LS_LONG_VIEW) { if (lflag & LS_LONG_VIEW) {
if ((lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) != 0 || if ((lflag & (LS_NUMERIC_VIEW|LS_SI_UNITS)) != 0 ||
can_get_users_groups_by_id(conn)) { sftp_can_get_users_groups_by_id(conn)) {
char *lname; char *lname;
struct stat sb; struct stat sb;
@ -916,7 +928,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
if (!(lflag & LS_LONG_VIEW) && (c != 1)) if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n"); printf("\n");
free_sftp_dirents(d); sftp_free_dirents(d);
return (0); return (0);
} }
@ -1070,7 +1082,7 @@ do_df(struct sftp_conn *conn, const char *path, int hflag, int iflag)
char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE]; char s_root[FMT_SCALED_STRSIZE], s_total[FMT_SCALED_STRSIZE];
char s_icapacity[16], s_dcapacity[16]; char s_icapacity[16], s_dcapacity[16];
if (do_statvfs(conn, path, &st, 1) == -1) if (sftp_statvfs(conn, path, &st, 1) == -1)
return -1; return -1;
if (st.f_files == 0) if (st.f_files == 0)
strlcpy(s_icapacity, "ERR", sizeof(s_icapacity)); strlcpy(s_icapacity, "ERR", sizeof(s_icapacity));
@ -1544,7 +1556,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
int lflag = 0, pflag = 0, rflag = 0, sflag = 0; int lflag = 0, pflag = 0, rflag = 0, sflag = 0;
int cmdnum, i; int cmdnum, i;
unsigned long n_arg = 0; unsigned long n_arg = 0;
Attrib a, *aa; Attrib a, aa;
char path_buf[PATH_MAX]; char path_buf[PATH_MAX];
int err = 0; int err = 0;
glob_t g; glob_t g;
@ -1585,23 +1597,24 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
rflag, aflag, fflag); rflag, aflag, fflag);
break; break;
case I_COPY: case I_COPY:
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd); path2 = sftp_make_absolute(path2, *pwd);
err = do_copy(conn, path1, path2); err = sftp_copy(conn, path1, path2);
break; break;
case I_RENAME: case I_RENAME:
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd); path2 = sftp_make_absolute(path2, *pwd);
err = do_rename(conn, path1, path2, lflag); err = sftp_rename(conn, path1, path2, lflag);
break; break;
case I_SYMLINK: case I_SYMLINK:
sflag = 1; sflag = 1;
/* FALLTHROUGH */ /* FALLTHROUGH */
case I_LINK: case I_LINK:
if (!sflag) if (!sflag)
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd); path2 = sftp_make_absolute(path2, *pwd);
err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2); err = (sflag ? sftp_symlink : sftp_hardlink)(conn,
path1, path2);
break; break;
case I_RM: case I_RM:
path1 = make_absolute_pwd_glob(path1, *pwd); path1 = make_absolute_pwd_glob(path1, *pwd);
@ -1609,42 +1622,42 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!quiet) if (!quiet)
mprintf("Removing %s\n", g.gl_pathv[i]); mprintf("Removing %s\n", g.gl_pathv[i]);
err = do_rm(conn, g.gl_pathv[i]); err = sftp_rm(conn, g.gl_pathv[i]);
if (err != 0 && err_abort) if (err != 0 && err_abort)
break; break;
} }
break; break;
case I_MKDIR: case I_MKDIR:
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
attrib_clear(&a); attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS; a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777; a.perm = 0777;
err = do_mkdir(conn, path1, &a, 1); err = sftp_mkdir(conn, path1, &a, 1);
break; break;
case I_RMDIR: case I_RMDIR:
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
err = do_rmdir(conn, path1); err = sftp_rmdir(conn, path1);
break; break;
case I_CHDIR: case I_CHDIR:
if (path1 == NULL || *path1 == '\0') if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir); path1 = xstrdup(startdir);
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
if ((tmp = do_realpath(conn, path1)) == NULL) { if ((tmp = sftp_realpath(conn, path1)) == NULL) {
err = 1; err = 1;
break; break;
} }
if ((aa = do_stat(conn, tmp, 0)) == NULL) { if (sftp_stat(conn, tmp, 0, &aa) != 0) {
free(tmp); free(tmp);
err = 1; err = 1;
break; break;
} }
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) { if (!(aa.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
error("Can't change directory: Can't check target"); error("Can't change directory: Can't check target");
free(tmp); free(tmp);
err = 1; err = 1;
break; break;
} }
if (!S_ISDIR(aa->perm)) { if (!S_ISDIR(aa.perm)) {
error("Can't change directory: \"%s\" is not " error("Can't change directory: \"%s\" is not "
"a directory", tmp); "a directory", tmp);
free(tmp); free(tmp);
@ -1672,7 +1685,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
/* Default to current directory if no path specified */ /* Default to current directory if no path specified */
if (path1 == NULL) if (path1 == NULL)
path1 = xstrdup(*pwd); path1 = xstrdup(*pwd);
path1 = make_absolute(path1, *pwd); path1 = sftp_make_absolute(path1, *pwd);
err = do_df(conn, path1, hflag, iflag); err = do_df(conn, path1, hflag, iflag);
break; break;
case I_LCHDIR: case I_LCHDIR:
@ -1714,7 +1727,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
if (!quiet) if (!quiet)
mprintf("Changing mode on %s\n", mprintf("Changing mode on %s\n",
g.gl_pathv[i]); g.gl_pathv[i]);
err = (hflag ? do_lsetstat : do_setstat)(conn, err = (hflag ? sftp_lsetstat : sftp_setstat)(conn,
g.gl_pathv[i], &a); g.gl_pathv[i], &a);
if (err != 0 && err_abort) if (err != 0 && err_abort)
break; break;
@ -1725,15 +1738,15 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
path1 = make_absolute_pwd_glob(path1, *pwd); path1 = make_absolute_pwd_glob(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g); remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!(aa = (hflag ? do_lstat : do_stat)(conn, if ((hflag ? sftp_lstat : sftp_stat)(conn,
g.gl_pathv[i], 0))) { g.gl_pathv[i], 0, &aa) != 0) {
if (err_abort) { if (err_abort) {
err = -1; err = -1;
break; break;
} else } else
continue; continue;
} }
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) { if (!(aa.flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of " error("Can't get current ownership of "
"remote file \"%s\"", g.gl_pathv[i]); "remote file \"%s\"", g.gl_pathv[i]);
if (err_abort) { if (err_abort) {
@ -1742,20 +1755,20 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
} else } else
continue; continue;
} }
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID; aa.flags &= SSH2_FILEXFER_ATTR_UIDGID;
if (cmdnum == I_CHOWN) { if (cmdnum == I_CHOWN) {
if (!quiet) if (!quiet)
mprintf("Changing owner on %s\n", mprintf("Changing owner on %s\n",
g.gl_pathv[i]); g.gl_pathv[i]);
aa->uid = n_arg; aa.uid = n_arg;
} else { } else {
if (!quiet) if (!quiet)
mprintf("Changing group on %s\n", mprintf("Changing group on %s\n",
g.gl_pathv[i]); g.gl_pathv[i]);
aa->gid = n_arg; aa.gid = n_arg;
} }
err = (hflag ? do_lsetstat : do_setstat)(conn, err = (hflag ? sftp_lsetstat : sftp_setstat)(conn,
g.gl_pathv[i], aa); g.gl_pathv[i], &aa);
if (err != 0 && err_abort) if (err != 0 && err_abort)
break; break;
} }
@ -2234,16 +2247,15 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
} }
#endif /* USE_LIBEDIT */ #endif /* USE_LIBEDIT */
remote_path = do_realpath(conn, "."); if ((remote_path = sftp_realpath(conn, ".")) == NULL)
if (remote_path == NULL)
fatal("Need cwd"); fatal("Need cwd");
startdir = xstrdup(remote_path); startdir = xstrdup(remote_path);
if (file1 != NULL) { if (file1 != NULL) {
dir = xstrdup(file1); dir = xstrdup(file1);
dir = make_absolute(dir, remote_path); dir = sftp_make_absolute(dir, remote_path);
if (remote_is_dir(conn, dir) && file2 == NULL) { if (sftp_remote_is_dir(conn, dir) && file2 == NULL) {
if (!quiet) if (!quiet)
mprintf("Changing to: %s\n", dir); mprintf("Changing to: %s\n", dir);
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir); snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
@ -2652,7 +2664,7 @@ main(int argc, char **argv)
} }
freeargs(&args); freeargs(&args);
conn = do_init(in, out, copy_buffer_len, num_requests, limit_kbps); conn = sftp_init(in, out, copy_buffer_len, num_requests, limit_kbps);
if (conn == NULL) if (conn == NULL)
fatal("Couldn't initialise connection to server"); fatal("Couldn't initialise connection to server");