=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/ssh/sftp-client.c,v retrieving revision 1.172 retrieving revision 1.173 diff -u -r1.172 -r1.173 --- src/usr.bin/ssh/sftp-client.c 2023/09/08 05:50:12 1.172 +++ src/usr.bin/ssh/sftp-client.c 2023/09/08 05:56:13 1.173 @@ -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 * @@ -322,16 +322,17 @@ 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); @@ -352,21 +353,24 @@ 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 @@ -429,7 +433,7 @@ } 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; @@ -540,7 +544,7 @@ /* 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 */ @@ -594,7 +598,7 @@ } 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; @@ -648,7 +652,7 @@ } 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; @@ -676,7 +680,7 @@ 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; @@ -801,16 +805,16 @@ 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; } @@ -819,12 +823,12 @@ } 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; @@ -839,7 +843,7 @@ } int -do_rm(struct sftp_conn *conn, const char *path) +sftp_rm(struct sftp_conn *conn, const char *path) { u_int status, id; @@ -854,7 +858,7 @@ } 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; @@ -872,7 +876,7 @@ } int -do_rmdir(struct sftp_conn *conn, const char *path) +sftp_rmdir(struct sftp_conn *conn, const char *path) { u_int status, id; @@ -889,8 +893,8 @@ 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; @@ -902,33 +906,31 @@ 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; @@ -938,12 +940,12 @@ 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; @@ -961,7 +963,7 @@ } 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; @@ -981,7 +983,7 @@ /* 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; @@ -1056,31 +1058,31 @@ } 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; @@ -1094,14 +1096,14 @@ } /* 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; } @@ -1111,9 +1113,9 @@ } /* 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__); @@ -1147,7 +1149,7 @@ (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); @@ -1184,8 +1186,8 @@ /* 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); @@ -1193,7 +1195,7 @@ } 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; @@ -1238,7 +1240,7 @@ } 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; @@ -1276,7 +1278,7 @@ } 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; @@ -1312,7 +1314,7 @@ } 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; @@ -1345,7 +1347,7 @@ #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; @@ -1403,7 +1405,7 @@ #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; @@ -1434,7 +1436,7 @@ #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; @@ -1464,7 +1466,7 @@ #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; @@ -1572,7 +1574,7 @@ } 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) { @@ -1588,14 +1590,18 @@ 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) - return -1; + 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) @@ -1641,7 +1647,7 @@ 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); @@ -1816,14 +1822,14 @@ 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; @@ -1876,12 +1882,10 @@ 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)) { @@ -1904,7 +1908,7 @@ 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; } @@ -1914,8 +1918,8 @@ 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)) { @@ -1925,13 +1929,11 @@ 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; } @@ -1945,7 +1947,7 @@ 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", @@ -1977,20 +1979,20 @@ 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; } @@ -2003,7 +2005,7 @@ } 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) { @@ -2013,7 +2015,7 @@ 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; @@ -2049,19 +2051,19 @@ 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; } @@ -2085,7 +2087,7 @@ 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); @@ -2196,7 +2198,7 @@ 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) { @@ -2206,12 +2208,12 @@ /* 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); @@ -2229,7 +2231,7 @@ 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); @@ -2265,10 +2267,10 @@ */ 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; } @@ -2286,8 +2288,8 @@ 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; @@ -2316,7 +2318,7 @@ 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", @@ -2329,21 +2331,21 @@ 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; } @@ -2402,13 +2404,13 @@ *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. @@ -2423,7 +2425,7 @@ } 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) { @@ -2438,13 +2440,17 @@ 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) - return -1; + 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))) { @@ -2474,7 +2480,7 @@ 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; } @@ -2624,7 +2630,7 @@ /* 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, @@ -2636,17 +2642,17 @@ 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 @@ -2654,8 +2660,8 @@ 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); @@ -2675,7 +2681,7 @@ 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); @@ -2684,10 +2690,12 @@ return -1; } - if (dirattrib == NULL && - (dirattrib = do_stat(from, from_path, 1)) == NULL) { - error("stat remote \"%s\" failed", from_path); - return -1; + 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); @@ -2715,17 +2723,17 @@ * 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; } @@ -2735,8 +2743,8 @@ 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 || @@ -2751,10 +2759,10 @@ (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", @@ -2769,22 +2777,22 @@ 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; @@ -2797,13 +2805,13 @@ } 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) @@ -2815,7 +2823,7 @@ 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 || @@ -2911,7 +2919,7 @@ } 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; @@ -2930,13 +2938,13 @@ * 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 @@ -2944,34 +2952,22 @@ } 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);