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
* 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)
return NULL;
}
return do_init(*reminp, *remoutp,
return sftp_init(*reminp, *remoutp,
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(path + 2 + nslash);
}
if (can_expand_path(conn))
return do_expand_path(conn, path);
if (sftp_can_expand_path(conn))
return sftp_expand_path(conn, path);
/* No protocol extension */
error("server expand-path extension is required "
"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)
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) {
debug("target directory \"%s\" does not exist", target);
a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS;
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 */
target_is_dir = 1;
}
if (target_is_dir)
abs_dst = path_append(target, filename);
abs_dst = sftp_path_append(target, filename);
else {
abs_dst = target;
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);
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) {
error("failed to upload directory %s to %s", src, targ);
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);
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
* 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));
err = -1;
goto out;
@ -1621,17 +1621,17 @@ sink_sftp(int argc, char *dst, const char *src, struct sftp_conn *conn)
}
if (dst_is_dir)
abs_dst = path_append(dst, filename);
abs_dst = sftp_path_append(dst, filename);
else
abs_dst = xstrdup(dst);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst,
NULL, pflag, SFTP_PROGRESS_ONLY, 0, 0, 1, 1) == -1)
err = -1;
} 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)
err = -1;
}
@ -1993,7 +1993,7 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
cleanup_exit(255);
memset(&g, 0, sizeof(g));
targetisdir = remote_is_dir(to, target);
targetisdir = sftp_remote_is_dir(to, target);
if (!targetisdir && targetshouldbedirectory) {
error("%s: destination is not a directory", targ);
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
* 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));
err = -1;
goto out;
@ -2034,18 +2034,18 @@ throughlocal_sftp(struct sftp_conn *from, struct sftp_conn *to,
}
if (targetisdir)
abs_dst = path_append(target, filename);
abs_dst = sftp_path_append(target, filename);
else
abs_dst = xstrdup(target);
debug("Fetching %s to %s\n", g.gl_pathv[i], abs_dst);
if (globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (crossload_dir(from, to, g.gl_pathv[i], abs_dst,
if (sftp_globpath_is_dir(g.gl_pathv[i]) && iamrecursive) {
if (sftp_crossload_dir(from, to, g.gl_pathv[i], abs_dst,
NULL, pflag, SFTP_PROGRESS_ONLY, 1) == -1)
err = -1;
} else {
if (do_crossload(from, to, g.gl_pathv[i], abs_dst, NULL,
pflag) == -1)
if (sftp_crossload(from, to, g.gl_pathv[i], abs_dst,
NULL, pflag) == -1)
err = -1;
}
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>
*
@ -342,16 +342,17 @@ get_handle(struct sftp_conn *conn, u_int expected_id, size_t *len,
return handle;
}
/* XXX returning &static is error-prone. Refactor to fill *Attrib argument */
static Attrib *
get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
static int
get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet, Attrib *a)
{
struct sshbuf *msg;
u_int id;
u_char type;
int r;
static Attrib a;
Attrib attr;
if (a != NULL)
memset(a, '\0', sizeof(*a));
if ((msg = sshbuf_new()) == NULL)
fatal_f("sshbuf_new failed");
get_msg(conn, msg);
@ -372,21 +373,24 @@ get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
else
error("stat remote: %s", fx2txt(status));
sshbuf_free(msg);
return(NULL);
return -1;
} else if (type != SSH2_FXP_ATTRS) {
fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
SSH2_FXP_ATTRS, type);
}
if ((r = decode_attrib(msg, &a)) != 0) {
if ((r = decode_attrib(msg, &attr)) != 0) {
error_fr(r, "decode_attrib");
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",
type, id, a.flags, a.perm);
type, id, attr.flags, attr.perm);
sshbuf_free(msg);
return &a;
return 0;
}
static int
@ -449,7 +453,7 @@ get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
}
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_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 */
if (ret->exts & SFTP_EXT_LIMITS) {
struct sftp_limits limits;
if (do_limits(ret, &limits) != 0)
if (sftp_get_limits(ret, &limits) != 0)
fatal_f("limits failed");
/* If the caller did not specify, find a good value */
@ -614,7 +618,7 @@ sftp_proto_version(struct sftp_conn *conn)
}
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_char type;
@ -668,7 +672,7 @@ do_limits(struct sftp_conn *conn, struct sftp_limits *limits)
}
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;
struct sshbuf *msg;
@ -696,7 +700,7 @@ do_close(struct sftp_conn *conn, const u_char *handle, u_int handle_len)
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)
{
struct sshbuf *msg;
@ -821,16 +825,16 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
out:
sshbuf_free(msg);
do_close(conn, handle, handle_len);
sftp_close(conn, handle, handle_len);
free(handle);
if (status != 0 && dir != NULL) {
/* Don't return results on error */
free_sftp_dirents(*dir);
sftp_free_dirents(*dir);
*dir = NULL;
} else if (interrupted && dir != NULL && *dir != NULL) {
/* Don't return partial matches on interrupt */
free_sftp_dirents(*dir);
sftp_free_dirents(*dir);
*dir = xcalloc(1, sizeof(**dir));
**dir = NULL;
}
@ -839,12 +843,12 @@ do_lsreaddir(struct sftp_conn *conn, const char *path, int print_flag,
}
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;
@ -859,7 +863,7 @@ void free_sftp_dirents(SFTP_DIRENT **s)
}
int
do_rm(struct sftp_conn *conn, const char *path)
sftp_rm(struct sftp_conn *conn, const char *path)
{
u_int status, id;
@ -874,7 +878,7 @@ do_rm(struct sftp_conn *conn, const char *path)
}
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;
@ -892,7 +896,7 @@ do_mkdir(struct sftp_conn *conn, const char *path, Attrib *a, int print_flag)
}
int
do_rmdir(struct sftp_conn *conn, const char *path)
sftp_rmdir(struct sftp_conn *conn, const char *path)
{
u_int status, id;
@ -909,8 +913,8 @@ do_rmdir(struct sftp_conn *conn, const char *path)
return status == SSH2_FX_OK ? 0 : -1;
}
Attrib *
do_stat(struct sftp_conn *conn, const char *path, int quiet)
int
sftp_stat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
{
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,
path, strlen(path));
return(get_decode_stat(conn, id, quiet));
return get_decode_stat(conn, id, quiet, a);
}
Attrib *
do_lstat(struct sftp_conn *conn, const char *path, int quiet)
int
sftp_lstat(struct sftp_conn *conn, const char *path, int quiet, Attrib *a)
{
u_int id;
if (conn->version == 0) {
if (quiet)
debug("Server version does not support lstat operation");
else
logit("Server version does not support lstat operation");
return(do_stat(conn, path, quiet));
do_log2(quiet ? SYSLOG_LEVEL_DEBUG1 : SYSLOG_LEVEL_INFO,
"Server version does not support lstat operation");
return sftp_stat(conn, path, quiet, a);
}
id = conn->msg_id++;
send_string_request(conn, id, SSH2_FXP_LSTAT, path,
strlen(path));
return(get_decode_stat(conn, id, quiet));
return get_decode_stat(conn, id, quiet, a);
}
#ifdef notyet
Attrib *
do_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
int quiet)
int
sftp_fstat(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
int quiet, Attrib *a)
{
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,
handle_len);
return(get_decode_stat(conn, id, quiet));
return get_decode_stat(conn, id, quiet, a);
}
#endif
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;
@ -981,7 +983,7 @@ do_setstat(struct sftp_conn *conn, const char *path, Attrib *a)
}
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)
{
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 */
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;
u_int expected_id, count, id;
@ -1076,31 +1078,31 @@ do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
}
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
can_expand_path(struct sftp_conn *conn)
sftp_can_expand_path(struct sftp_conn *conn)
{
return (conn->exts & SFTP_EXT_PATH_EXPAND) != 0;
}
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");
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
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;
u_char *old_handle, *new_handle;
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 */
if ((a = do_stat(conn, oldpath, 0)) == NULL)
if (sftp_stat(conn, oldpath, 0, &attr) != 0)
return -1;
/* Do not preserve set[ug]id here, as we do not preserve ownership */
if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
mode = a->perm & 0777;
if (attr.flags & SSH2_FILEXFER_ATTR_PERMISSIONS) {
mode = attr.perm & 0777;
if (!S_ISREG(a->perm)) {
if (!S_ISREG(attr.perm)) {
error("Cannot copy non-regular file: %s", oldpath);
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 */
attrib_clear(a);
a->perm = mode;
a->flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
attrib_clear(&attr);
attr.perm = mode;
attr.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
if ((msg = sshbuf_new()) == NULL)
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_u32(msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|
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));
send_msg(conn, msg);
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 */
sshbuf_free(msg);
do_close(conn, old_handle, old_handle_len);
do_close(conn, new_handle, new_handle_len);
sftp_close(conn, old_handle, old_handle_len);
sftp_close(conn, new_handle, new_handle_len);
free(old_handle);
free(new_handle);
@ -1213,7 +1215,7 @@ do_copy(struct sftp_conn *conn, const char *oldpath, const char *newpath)
}
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)
{
struct sshbuf *msg;
@ -1258,7 +1260,7 @@ do_rename(struct sftp_conn *conn, const char *oldpath, const char *newpath,
}
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;
u_int status, id;
@ -1296,7 +1298,7 @@ do_hardlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
}
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;
u_int status, id;
@ -1332,7 +1334,7 @@ do_symlink(struct sftp_conn *conn, const char *oldpath, const char *newpath)
}
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;
u_int status, id;
@ -1365,7 +1367,7 @@ do_fsync(struct sftp_conn *conn, u_char *handle, u_int handle_len)
#ifdef notyet
char *
do_readlink(struct sftp_conn *conn, const char *path)
sftp_readlink(struct sftp_conn *conn, const char *path)
{
struct sshbuf *msg;
u_int expected_id, count, id;
@ -1423,7 +1425,7 @@ do_readlink(struct sftp_conn *conn, const char *path)
#endif
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)
{
struct sshbuf *msg;
@ -1454,7 +1456,7 @@ do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
#ifdef notyet
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 sshbuf *msg;
@ -1484,7 +1486,7 @@ do_fstatvfs(struct sftp_conn *conn, const u_char *handle, u_int handle_len,
#endif
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;
u_int status, id;
@ -1592,7 +1594,7 @@ progress_meter_path(const char *path)
}
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,
int fsync_flag, int inplace_flag)
{
@ -1608,14 +1610,18 @@ do_download(struct sftp_conn *conn, const char *remote_path,
struct requests requests;
struct request *req;
u_char type;
Attrib attr;
debug2_f("download remote \"%s\" to local \"%s\"",
remote_path, local_path);
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;
a = &attr;
}
/* Do not preserve set[ug]id here, as we do not preserve ownership */
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\": "
"local file is larger than remote", local_path);
fail:
do_close(conn, handle, handle_len);
sftp_close(conn, handle, handle_len);
free(handle);
if (local_fd != -1)
close(local_fd);
@ -1836,14 +1842,14 @@ do_download(struct sftp_conn *conn, const char *remote_path,
if (read_error) {
error("read remote \"%s\" : %s", remote_path, fx2txt(status));
status = -1;
do_close(conn, handle, handle_len);
sftp_close(conn, handle, handle_len);
} else if (write_error) {
error("write local \"%s\": %s", local_path,
strerror(write_errno));
status = SSH2_FX_FAILURE;
do_close(conn, handle, handle_len);
sftp_close(conn, handle, handle_len);
} else {
if (do_close(conn, handle, handle_len) != 0 || interrupted)
if (sftp_close(conn, handle, handle_len) != 0 || interrupted)
status = SSH2_FX_FAILURE;
else
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);
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);
return -1;
}
/* Don't let this be clobbered by later do_stat calls */
ldirattrib = *a;
dirattrib = &ldirattrib;
}
if (!S_ISDIR(dirattrib->perm)) {
@ -1928,7 +1932,7 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
return -1;
}
if (do_readdir(conn, src, &dir_entries) == -1) {
if (sftp_readdir(conn, src, &dir_entries) == -1) {
error("remote readdir \"%s\" failed", src);
return -1;
}
@ -1938,8 +1942,8 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
free(new_src);
filename = dir_entries[i]->filename;
new_dst = path_append(dst, filename);
new_src = path_append(src, filename);
new_dst = sftp_path_append(dst, filename);
new_src = sftp_path_append(src, filename);
a = &dir_entries[i]->a;
if (S_ISLNK(a->perm)) {
@ -1949,13 +1953,11 @@ download_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
continue;
}
/* 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);
ret = -1;
continue;
}
/* Don't let this be clobbered by later do_stat calls */
lsym = *a;
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)
ret = -1;
} 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,
inplace_flag) == -1) {
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,
strerror(errno));
free_sftp_dirents(dir_entries);
sftp_free_dirents(dir_entries);
return ret;
}
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,
int fsync_flag, int follow_link_flag, int inplace_flag)
{
char *src_canon;
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);
return -1;
}
@ -2027,7 +2029,7 @@ download_dir(struct sftp_conn *conn, const char *src, const char *dst,
}
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,
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;
struct sshbuf *msg;
struct stat sb;
Attrib a, t, *c = NULL;
Attrib a, t, c;
u_int32_t startid, ackid;
u_int64_t highwater = 0, maxack = 0;
struct request *ack = NULL;
@ -2073,19 +2075,19 @@ do_upload(struct sftp_conn *conn, const char *local_path,
if (resume) {
/* 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);
return -1;
}
if ((off_t)c->size >= sb.st_size) {
if ((off_t)c.size >= sb.st_size) {
error("resume \"%s\": destination file "
"same size or larger", local_path);
close(local_fd);
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);
return -1;
}
@ -2109,7 +2111,7 @@ do_upload(struct sftp_conn *conn, const char *local_path,
data = xmalloc(conn->upload_buflen);
/* Read from local and write to remote */
offset = progress_counter = (resume ? c->size : 0);
offset = progress_counter = (resume ? c.size : 0);
if (showprogress) {
start_progress_meter(progress_meter_path(local_path),
sb.st_size, &progress_counter);
@ -2221,7 +2223,7 @@ do_upload(struct sftp_conn *conn, const char *local_path,
attrib_clear(&t);
t.flags = SSH2_FILEXFER_ATTR_SIZE;
t.size = highwater;
do_fsetstat(conn, handle, handle_len, &t);
sftp_fsetstat(conn, handle, handle_len, &t);
}
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 */
if (preserve_flag)
do_fsetstat(conn, handle, handle_len, &a);
sftp_fsetstat(conn, handle, handle_len, &a);
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;
free(handle);
@ -2254,7 +2256,7 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
struct dirent *dp;
char *filename, *new_src = NULL, *new_dst = NULL;
struct stat sb;
Attrib a, *dirattrib;
Attrib a, dirattrib;
u_int32_t saved_perm;
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;
a.perm |= (S_IWUSR|S_IXUSR);
if (do_mkdir(conn, dst, &a, 0) != 0) {
if ((dirattrib = do_stat(conn, dst, 0)) == NULL)
if (sftp_mkdir(conn, dst, &a, 0) != 0) {
if (sftp_stat(conn, dst, 0, &dirattrib) != 0)
return -1;
if (!S_ISDIR(dirattrib->perm)) {
if (!S_ISDIR(dirattrib.perm)) {
error("\"%s\" exists but is not a directory", dst);
return -1;
}
@ -2311,8 +2313,8 @@ upload_dir_internal(struct sftp_conn *conn, const char *src, const char *dst,
free(new_dst);
free(new_src);
filename = dp->d_name;
new_dst = path_append(dst, filename);
new_src = path_append(src, filename);
new_dst = sftp_path_append(dst, filename);
new_src = sftp_path_append(src, filename);
if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0)
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)
ret = -1;
} 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,
inplace_flag) == -1) {
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_src);
do_setstat(conn, dst, &a);
sftp_setstat(conn, dst, &a);
(void) closedir(dirp);
return ret;
}
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 follow_link_flag, int inplace_flag)
{
char *dst_canon;
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);
return -1;
}
@ -2427,13 +2429,13 @@ handle_dest_replies(struct sftp_conn *to, const char *to_path, int synchronous,
*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
* high-water mark. ATM the only caller of this function (scp)
* doesn't support transfer resumption, so this doesn't matter
* 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
* server not to have reordered replies that could have
* 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
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,
Attrib *a, int preserve_flag)
{
@ -2463,13 +2465,17 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
struct requests requests;
struct request *req;
u_char type;
Attrib attr;
debug2_f("crossload src \"%s\" to dst \"%s\"", from_path, to_path);
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;
a = &attr;
}
if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
(!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",
SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC, a,
&to_handle, &to_handle_len) != 0) {
do_close(from, from_handle, from_handle_len);
sftp_close(from, from_handle, from_handle_len);
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 */
if (read_error || write_error || interrupted) {
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);
if (send_open(to, to_path, "dest",
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) {
error("read origin \"%s\": %s", from_path, fx2txt(status));
status = -1;
do_close(from, from_handle, from_handle_len);
sftp_close(from, from_handle, from_handle_len);
if (to_handle != NULL)
do_close(to, to_handle, to_handle_len);
sftp_close(to, to_handle, to_handle_len);
} else if (write_error) {
error("write dest \"%s\": %s", to_path, fx2txt(write_error));
status = SSH2_FX_FAILURE;
do_close(from, from_handle, from_handle_len);
sftp_close(from, from_handle, from_handle_len);
if (to_handle != NULL)
do_close(to, to_handle, to_handle_len);
sftp_close(to, to_handle, to_handle_len);
} else {
if (do_close(from, from_handle, from_handle_len) != 0 ||
if (sftp_close(from, from_handle, from_handle_len) != 0 ||
interrupted)
status = -1;
else
@ -2679,8 +2685,8 @@ do_crossload(struct sftp_conn *from, struct sftp_conn *to,
if (to_handle != NULL) {
/* Need to resend utimes after write */
if (preserve_flag)
do_fsetstat(to, to_handle, to_handle_len, a);
do_close(to, to_handle, to_handle_len);
sftp_fsetstat(to, to_handle, to_handle_len, a);
sftp_close(to, to_handle, to_handle_len);
}
}
sshbuf_free(msg);
@ -2700,7 +2706,7 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
SFTP_DIRENT **dir_entries;
char *filename, *new_from_path = NULL, *new_to_path = NULL;
mode_t mode = 0777;
Attrib curdir;
Attrib curdir, ldirattrib, newdir;
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;
}
if (dirattrib == NULL &&
(dirattrib = do_stat(from, from_path, 1)) == NULL) {
if (dirattrib == NULL) {
if (sftp_stat(from, from_path, 1, &ldirattrib) != 0) {
error("stat remote \"%s\" failed", from_path);
return -1;
}
dirattrib = &ldirattrib;
}
if (!S_ISDIR(dirattrib->perm)) {
error("\"%s\" is not a directory", from_path);
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
* write to the directory we create for the duration of the transfer.
*/
if (do_mkdir(to, to_path, &curdir, 0) != 0) {
if ((dirattrib = do_stat(to, to_path, 0)) == NULL)
if (sftp_mkdir(to, to_path, &curdir, 0) != 0) {
if (sftp_stat(to, to_path, 0, &newdir) != 0)
return -1;
if (!S_ISDIR(dirattrib->perm)) {
if (!S_ISDIR(newdir.perm)) {
error("\"%s\" exists but is not a directory", to_path);
return -1;
}
}
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);
return -1;
}
@ -2760,8 +2768,8 @@ crossload_dir_internal(struct sftp_conn *from, struct sftp_conn *to,
free(new_to_path);
filename = dir_entries[i]->filename;
new_from_path = path_append(from_path, filename);
new_to_path = path_append(to_path, filename);
new_from_path = sftp_path_append(from_path, filename);
new_to_path = sftp_path_append(to_path, filename);
if (S_ISDIR(dir_entries[i]->a.perm)) {
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))) {
/*
* 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.
*/
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 :
&(dir_entries[i]->a), preserve_flag) == -1) {
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_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;
}
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,
Attrib *dirattrib, int preserve_flag, int print_flag, int follow_link_flag)
{
char *from_path_canon;
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",
from_path);
return -1;
@ -2822,13 +2830,13 @@ crossload_dir(struct sftp_conn *from, struct sftp_conn *to,
}
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;
}
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 *gids, u_int ngids,
char ***usernamesp, char ***groupnamesp)
@ -2840,7 +2848,7 @@ do_get_users_groups_by_id(struct sftp_conn *conn,
int r;
*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;
if ((msg = sshbuf_new()) == NULL ||
@ -2936,7 +2944,7 @@ do_get_users_groups_by_id(struct sftp_conn *conn,
}
char *
path_append(const char *p1, const char *p2)
sftp_path_append(const char *p1, const char *p2)
{
char *ret;
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.
*/
char *
make_absolute(char *p, const char *pwd)
sftp_make_absolute(char *p, const char *pwd)
{
char *abs_str;
/* Derelativise */
if (p && !path_absolute(p)) {
abs_str = path_append(pwd, p);
abs_str = sftp_path_append(pwd, p);
free(p);
return(abs_str);
} else
@ -2969,34 +2977,22 @@ make_absolute(char *p, const char *pwd)
}
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? */
if ((a = do_stat(conn, path, 1)) == NULL)
if (sftp_stat(conn, path, 1, &a) != 0)
return(0);
if (!(a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
if (!(a.flags & SSH2_FILEXFER_ATTR_PERMISSIONS))
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 */
int
globpath_is_dir(const char *pathname)
sftp_globpath_is_dir(const char *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>
@ -70,107 +70,106 @@ struct sftp_limits {
* Initialise a SSH filexfer connection. Returns NULL on error or
* 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 *);
/* 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' */
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' */
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) */
void free_sftp_dirents(SFTP_DIRENT **);
/* Frees a NULL-terminated array of SFTP_DIRENTs (eg. from sftp_readdir) */
void sftp_free_dirents(SFTP_DIRENT **);
/* Delete file 'path' */
int do_rm(struct sftp_conn *, const char *);
int sftp_rm(struct sftp_conn *, const char *);
/* 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' */
int do_rmdir(struct sftp_conn *, const char *);
int sftp_rmdir(struct sftp_conn *, const char *);
/* 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) */
Attrib *do_lstat(struct sftp_conn *, const char *, int);
int sftp_lstat(struct sftp_conn *, const char *, int, Attrib *);
/* 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' */
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 */
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 */
char *do_realpath(struct sftp_conn *, const char *);
char *sftp_realpath(struct sftp_conn *, const char *);
/* 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 */
int can_expand_path(struct sftp_conn *);
int sftp_can_expand_path(struct sftp_conn *);
/* 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' */
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' */
int do_copy(struct sftp_conn *, const char *, const char *);
int sftp_copy(struct sftp_conn *, const char *, const char *);
/* 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' */
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' */
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
* 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);
/*
* Recursively download 'remote_directory' to 'local_directory'. Preserve
* 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);
/*
* Upload 'local_path' to 'remote_path'. Preserve permissions and times
* 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);
/*
* Recursively upload 'local_directory' to 'remote_directory'. Preserve
* 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);
/*
* Download a 'from_path' from the 'from' connection and upload it to
* to 'to' connection at 'to_path'.
*/
int
do_crossload(struct sftp_conn *from, struct sftp_conn *to,
int sftp_crossload(struct sftp_conn *from, struct sftp_conn *to,
const char *from_path, const char *to_path,
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'
* 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,
Attrib *dirattrib, int preserve_flag, int print_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.
*/
int can_get_users_groups_by_id(struct sftp_conn *conn);
int do_get_users_groups_by_id(struct sftp_conn *conn,
int sftp_can_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 *gids, u_int ngids,
char ***usernamesp, char ***groupnamesp);
/* 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
* 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 */
int remote_is_dir(struct sftp_conn *conn, const char *path);
/* Check if local path is directory */
int local_is_dir(const char *path);
int sftp_remote_is_dir(struct sftp_conn *conn, const char *path);
/* 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

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>
*
@ -51,7 +51,7 @@ fudge_opendir(const char *path)
r = xcalloc(1, sizeof(*r));
if (do_readdir(cur.conn, path, &r->dir)) {
if (sftp_readdir(cur.conn, path, &r->dir)) {
free(r);
return(NULL);
}
@ -103,32 +103,32 @@ fudge_readdir(struct SFTP_OPENDIR *od)
static void
fudge_closedir(struct SFTP_OPENDIR *od)
{
free_sftp_dirents(od->dir);
sftp_free_dirents(od->dir);
free(od);
}
static int
fudge_lstat(const char *path, struct stat *st)
{
Attrib *a;
Attrib a;
if (!(a = do_lstat(cur.conn, path, 1)))
return(-1);
if (sftp_lstat(cur.conn, path, 1, &a) != 0)
return -1;
attrib_to_stat(a, st);
attrib_to_stat(&a, st);
return(0);
return 0;
}
static int
fudge_stat(const char *path, struct stat *st)
{
Attrib *a;
Attrib a;
if (!(a = do_stat(cur.conn, path, 1)))
return(-1);
if (sftp_stat(cur.conn, path, 1, &a) != 0)
return -1;
attrib_to_stat(a, st);
attrib_to_stat(&a, st);
return(0);
}

View File

@ -106,9 +106,9 @@ lookup_and_record(struct sftp_conn *conn,
u_int i;
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) {
debug_fr(r, "do_get_users_groups_by_id");
debug_fr(r, "sftp_get_users_groups_by_id");
return;
}
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;
if (!can_get_users_groups_by_id(conn))
if (!sftp_can_get_users_groups_by_id(conn))
return;
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;
if (!can_get_users_groups_by_id(conn))
if (!sftp_can_get_users_groups_by_id(conn))
return;
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>
*
@ -628,11 +628,21 @@ make_absolute_pwd_glob(char *p, const char *pwd)
escpwd = escape_glob(pwd);
if (p == NULL)
return escpwd;
ret = make_absolute(p, escpwd);
ret = sftp_make_absolute(p, escpwd);
free(escpwd);
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
process_get(struct sftp_conn *conn, const char *src, const char *dst,
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 (local_is_dir(dst)) {
abs_dst = path_append(dst, filename);
abs_dst = sftp_path_append(dst, filename);
} else {
abs_dst = xstrdup(dst);
}
} else if (dst) {
abs_dst = path_append(dst, filename);
abs_dst = sftp_path_append(dst, filename);
} else {
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",
g.gl_pathv[i], abs_dst);
/* XXX follow link flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (download_dir(conn, g.gl_pathv[i], abs_dst, NULL,
pflag || global_pflag, 1, resume,
if (sftp_globpath_is_dir(g.gl_pathv[i]) &&
(rflag || global_rflag)) {
if (sftp_download_dir(conn, g.gl_pathv[i], abs_dst,
NULL, pflag || global_pflag, 1, resume,
fflag || global_fflag, 0, 0) == -1)
err = -1;
} 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,
fflag || global_fflag, 0) == -1)
err = -1;
@ -731,7 +742,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
if (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));
@ -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 (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 (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 directory specified, append filename */
if (dst_is_dir)
abs_dst = path_append(tmp_dst, filename);
abs_dst = sftp_path_append(tmp_dst, filename);
else
abs_dst = xstrdup(tmp_dst);
} else if (tmp_dst) {
abs_dst = path_append(tmp_dst, filename);
abs_dst = sftp_path_append(tmp_dst, filename);
} else {
abs_dst = make_absolute(xstrdup(filename), pwd);
abs_dst = sftp_make_absolute(xstrdup(filename), pwd);
}
free(tmp);
@ -792,13 +803,14 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst,
mprintf("Uploading %s to %s\n",
g.gl_pathv[i], abs_dst);
/* XXX follow_link_flag */
if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
if (upload_dir(conn, g.gl_pathv[i], abs_dst,
if (sftp_globpath_is_dir(g.gl_pathv[i]) &&
(rflag || global_rflag)) {
if (sftp_upload_dir(conn, g.gl_pathv[i], abs_dst,
pflag || global_pflag, 1, resume,
fflag || global_fflag, 0, 0) == -1)
err = -1;
} 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,
fflag || global_fflag, 0) == -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;
SFTP_DIRENT **d;
if ((n = do_readdir(conn, path, &d)) != 0)
if ((n = sftp_readdir(conn, path, &d)) != 0)
return (n);
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))
continue;
tmp = path_append(path, d[n]->filename);
tmp = sftp_path_append(path, d[n]->filename);
fname = path_strip(tmp, strip_path);
free(tmp);
if (lflag & LS_LONG_VIEW) {
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;
struct stat sb;
@ -916,7 +928,7 @@ do_ls_dir(struct sftp_conn *conn, const char *path,
if (!(lflag & LS_LONG_VIEW) && (c != 1))
printf("\n");
free_sftp_dirents(d);
sftp_free_dirents(d);
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_icapacity[16], s_dcapacity[16];
if (do_statvfs(conn, path, &st, 1) == -1)
if (sftp_statvfs(conn, path, &st, 1) == -1)
return -1;
if (st.f_files == 0)
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 cmdnum, i;
unsigned long n_arg = 0;
Attrib a, *aa;
Attrib a, aa;
char path_buf[PATH_MAX];
int err = 0;
glob_t g;
@ -1585,23 +1597,24 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
rflag, aflag, fflag);
break;
case I_COPY:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_copy(conn, path1, path2);
path1 = sftp_make_absolute(path1, *pwd);
path2 = sftp_make_absolute(path2, *pwd);
err = sftp_copy(conn, path1, path2);
break;
case I_RENAME:
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = do_rename(conn, path1, path2, lflag);
path1 = sftp_make_absolute(path1, *pwd);
path2 = sftp_make_absolute(path2, *pwd);
err = sftp_rename(conn, path1, path2, lflag);
break;
case I_SYMLINK:
sflag = 1;
/* FALLTHROUGH */
case I_LINK:
if (!sflag)
path1 = make_absolute(path1, *pwd);
path2 = make_absolute(path2, *pwd);
err = (sflag ? do_symlink : do_hardlink)(conn, path1, path2);
path1 = sftp_make_absolute(path1, *pwd);
path2 = sftp_make_absolute(path2, *pwd);
err = (sflag ? sftp_symlink : sftp_hardlink)(conn,
path1, path2);
break;
case I_RM:
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++) {
if (!quiet)
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)
break;
}
break;
case I_MKDIR:
path1 = make_absolute(path1, *pwd);
path1 = sftp_make_absolute(path1, *pwd);
attrib_clear(&a);
a.flags |= SSH2_FILEXFER_ATTR_PERMISSIONS;
a.perm = 0777;
err = do_mkdir(conn, path1, &a, 1);
err = sftp_mkdir(conn, path1, &a, 1);
break;
case I_RMDIR:
path1 = make_absolute(path1, *pwd);
err = do_rmdir(conn, path1);
path1 = sftp_make_absolute(path1, *pwd);
err = sftp_rmdir(conn, path1);
break;
case I_CHDIR:
if (path1 == NULL || *path1 == '\0')
path1 = xstrdup(startdir);
path1 = make_absolute(path1, *pwd);
if ((tmp = do_realpath(conn, path1)) == NULL) {
path1 = sftp_make_absolute(path1, *pwd);
if ((tmp = sftp_realpath(conn, path1)) == NULL) {
err = 1;
break;
}
if ((aa = do_stat(conn, tmp, 0)) == NULL) {
if (sftp_stat(conn, tmp, 0, &aa) != 0) {
free(tmp);
err = 1;
break;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
if (!(aa.flags & SSH2_FILEXFER_ATTR_PERMISSIONS)) {
error("Can't change directory: Can't check target");
free(tmp);
err = 1;
break;
}
if (!S_ISDIR(aa->perm)) {
if (!S_ISDIR(aa.perm)) {
error("Can't change directory: \"%s\" is not "
"a directory", 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 */
if (path1 == NULL)
path1 = xstrdup(*pwd);
path1 = make_absolute(path1, *pwd);
path1 = sftp_make_absolute(path1, *pwd);
err = do_df(conn, path1, hflag, iflag);
break;
case I_LCHDIR:
@ -1714,7 +1727,7 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
if (!quiet)
mprintf("Changing mode on %s\n",
g.gl_pathv[i]);
err = (hflag ? do_lsetstat : do_setstat)(conn,
err = (hflag ? sftp_lsetstat : sftp_setstat)(conn,
g.gl_pathv[i], &a);
if (err != 0 && err_abort)
break;
@ -1725,15 +1738,15 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
path1 = make_absolute_pwd_glob(path1, *pwd);
remote_glob(conn, path1, GLOB_NOCHECK, NULL, &g);
for (i = 0; g.gl_pathv[i] && !interrupted; i++) {
if (!(aa = (hflag ? do_lstat : do_stat)(conn,
g.gl_pathv[i], 0))) {
if ((hflag ? sftp_lstat : sftp_stat)(conn,
g.gl_pathv[i], 0, &aa) != 0) {
if (err_abort) {
err = -1;
break;
} else
continue;
}
if (!(aa->flags & SSH2_FILEXFER_ATTR_UIDGID)) {
if (!(aa.flags & SSH2_FILEXFER_ATTR_UIDGID)) {
error("Can't get current ownership of "
"remote file \"%s\"", g.gl_pathv[i]);
if (err_abort) {
@ -1742,20 +1755,20 @@ parse_dispatch_command(struct sftp_conn *conn, const char *cmd, char **pwd,
} else
continue;
}
aa->flags &= SSH2_FILEXFER_ATTR_UIDGID;
aa.flags &= SSH2_FILEXFER_ATTR_UIDGID;
if (cmdnum == I_CHOWN) {
if (!quiet)
mprintf("Changing owner on %s\n",
g.gl_pathv[i]);
aa->uid = n_arg;
aa.uid = n_arg;
} else {
if (!quiet)
mprintf("Changing group on %s\n",
g.gl_pathv[i]);
aa->gid = n_arg;
aa.gid = n_arg;
}
err = (hflag ? do_lsetstat : do_setstat)(conn,
g.gl_pathv[i], aa);
err = (hflag ? sftp_lsetstat : sftp_setstat)(conn,
g.gl_pathv[i], &aa);
if (err != 0 && err_abort)
break;
}
@ -2234,16 +2247,15 @@ interactive_loop(struct sftp_conn *conn, char *file1, char *file2)
}
#endif /* USE_LIBEDIT */
remote_path = do_realpath(conn, ".");
if (remote_path == NULL)
if ((remote_path = sftp_realpath(conn, ".")) == NULL)
fatal("Need cwd");
startdir = xstrdup(remote_path);
if (file1 != NULL) {
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)
mprintf("Changing to: %s\n", dir);
snprintf(cmd, sizeof cmd, "cd \"%s\"", dir);
@ -2652,7 +2664,7 @@ main(int argc, char **argv)
}
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)
fatal("Couldn't initialise connection to server");