11305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* $OpenBSD: sftp-client.c,v 1.94 2010/12/04 00:18:01 djm Exp $ */ 21305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* 31305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org> 41305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 51305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Permission to use, copy, modify, and distribute this software for any 61305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * purpose with or without fee is hereby granted, provided that the above 71305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * copyright notice and this permission notice appear in all copies. 81305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * 91305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* XXX: memleaks */ 191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* XXX: signed vs unsigned */ 201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* XXX: remove all logging, only return status codes */ 211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* XXX: copy between two remote sites */ 221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "includes.h" 241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/types.h> 261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/param.h> 271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_SYS_STATVFS_H 281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/statvfs.h> 291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif 301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "openbsd-compat/sys-queue.h" 311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_SYS_STAT_H 321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# include <sys/stat.h> 331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif 341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_SYS_TIME_H 351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood# include <sys/time.h> 361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif 371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <sys/uio.h> 381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <dirent.h> 401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <errno.h> 411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <fcntl.h> 421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <signal.h> 431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdarg.h> 441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <stdio.h> 451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <string.h> 461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include <unistd.h> 471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "xmalloc.h" 491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "buffer.h" 501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "log.h" 511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "atomicio.h" 521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "progressmeter.h" 531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "misc.h" 541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "sftp.h" 561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "sftp-common.h" 571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#include "sftp-client.h" 581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodextern volatile sig_atomic_t interrupted; 601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodextern int showprogress; 611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Minimum amount of data to read at a time */ 631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define MIN_READ_SIZE 512 641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* Maximum depth to descend in directory trees */ 661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define MAX_DIR_DEPTH 64 671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstruct sftp_conn { 691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int fd_in; 701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int fd_out; 711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int transfer_buflen; 721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int num_requests; 731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int version; 741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int msg_id; 751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define SFTP_EXT_POSIX_RENAME 0x00000001 761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define SFTP_EXT_STATVFS 0x00000002 771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define SFTP_EXT_FSTATVFS 0x00000004 781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#define SFTP_EXT_HARDLINK 0x00000008 791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int exts; 801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int64_t limit_kbps; 811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct bwlimit bwlimit_in, bwlimit_out; 821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood}; 831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char * 851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodget_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, 861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood const char *errfmt, ...) __attribute__((format(printf, 4, 5))); 871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood/* ARGSUSED */ 891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int 901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsftpio(void *_bwlimit, size_t amount) 911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit; 931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood bandwidth_limit(bwlimit, amount); 951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return 0; 961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void 991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsend_msg(struct sftp_conn *conn, Buffer *m) 1001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 1011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_char mlen[4]; 1021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct iovec iov[2]; 1031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (buffer_len(m) > SFTP_MAX_MSG_LENGTH) 1051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Outbound message too long %u", buffer_len(m)); 1061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send length first */ 1081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood put_u32(mlen, buffer_len(m)); 1091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood iov[0].iov_base = mlen; 1101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood iov[0].iov_len = sizeof(mlen); 1111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood iov[1].iov_base = buffer_ptr(m); 1121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood iov[1].iov_len = buffer_len(m); 1131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (atomiciov6(writev, conn->fd_out, iov, 2, 1151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) != 1161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_len(m) + sizeof(mlen)) 1171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Couldn't send packet: %s", strerror(errno)); 1181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(m); 1201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 1211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void 1231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodget_msg(struct sftp_conn *conn, Buffer *m) 1241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 1251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int msg_len; 1261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_append_space(m, 4); 1281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4, 1291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) { 1301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (errno == EPIPE) 1311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Connection closed"); 1321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 1331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Couldn't read packet: %s", strerror(errno)); 1341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood msg_len = buffer_get_int(m); 1371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (msg_len > SFTP_MAX_MSG_LENGTH) 1381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Received message too long %u", msg_len); 1391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_append_space(m, msg_len); 1411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len, 1421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) 1431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood != msg_len) { 1441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (errno == EPIPE) 1451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Connection closed"); 1461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 1471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Read packet: %s", strerror(errno)); 1481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 1491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 1501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void 1521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsend_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s, 1531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int len) 1541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 1551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 1561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 1581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, code); 1591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 1601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, s, len); 1611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 1621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 1631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 1641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 1651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void 1671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsend_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code, 1681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *s, u_int len, Attrib *a) 1691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 1701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 1711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 1731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, code); 1741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 1751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, s, len); 1761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood encode_attrib(&msg, a); 1771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 1781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id); 1791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 1801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 1811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic u_int 1831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodget_status(struct sftp_conn *conn, u_int expected_id) 1841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 1851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 1861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type, id, status; 1871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 1891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 1901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 1911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 1921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 1941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("ID mismatch (%u != %u)", id, expected_id); 1951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type != SSH2_FXP_STATUS) 1961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u", 1971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_STATUS, type); 1981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = buffer_get_int(&msg); 2001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 2011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("SSH2_FXP_STATUS %u", status); 2031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return status; 2051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 2061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic char * 2081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodget_handle(struct sftp_conn *conn, u_int expected_id, u_int *len, 2091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood const char *errfmt, ...) 2101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 2111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 2121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type, id; 2131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *handle, errmsg[256]; 2141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood va_list args; 2151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int status; 2161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood va_start(args, errfmt); 2181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (errfmt != NULL) 2191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood vsnprintf(errmsg, sizeof(errmsg), errfmt, args); 2201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood va_end(args); 2211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 2231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 2241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 2251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 2261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 2281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("%s: ID mismatch (%u != %u)", 2291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errfmt == NULL ? __func__ : errmsg, id, expected_id); 2301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type == SSH2_FXP_STATUS) { 2311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = buffer_get_int(&msg); 2321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (errfmt != NULL) 2331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("%s: %s", errmsg, fx2txt(status)); 2341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 2351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(NULL); 2361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (type != SSH2_FXP_HANDLE) 2371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u", 2381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type); 2391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood handle = buffer_get_string(&msg, len); 2411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 2421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(handle); 2441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 2451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic Attrib * 2471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodget_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet) 2481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 2491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 2501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type, id; 2511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *a; 2521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 2541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 2551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 2571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 2581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received stat reply T:%u I:%u", type, id); 2601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 2611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("ID mismatch (%u != %u)", id, expected_id); 2621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type == SSH2_FXP_STATUS) { 2631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int status = buffer_get_int(&msg); 2641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (quiet) 2661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug("Couldn't stat remote file: %s", fx2txt(status)); 2671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 2681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't stat remote file: %s", fx2txt(status)); 2691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 2701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(NULL); 2711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (type != SSH2_FXP_ATTRS) { 2721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u", 2731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_ATTRS, type); 2741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 2751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a = decode_attrib(&msg); 2761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 2771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(a); 2791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 2801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int 2821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodget_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st, 2831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int expected_id, int quiet) 2841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 2851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 2861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type, id, flag; 2871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 2891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 2901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 2921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 2931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 2941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received statvfs reply T:%u I:%u", type, id); 2951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 2961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("ID mismatch (%u != %u)", id, expected_id); 2971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type == SSH2_FXP_STATUS) { 2981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int status = buffer_get_int(&msg); 2991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (quiet) 3011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug("Couldn't statvfs: %s", fx2txt(status)); 3021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 3031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't statvfs: %s", fx2txt(status)); 3041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 3051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 3061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (type != SSH2_FXP_EXTENDED_REPLY) { 3071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u", 3081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_EXTENDED_REPLY, type); 3091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 3101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood bzero(st, sizeof(*st)); 3121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_bsize = buffer_get_int64(&msg); 3131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_frsize = buffer_get_int64(&msg); 3141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_blocks = buffer_get_int64(&msg); 3151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_bfree = buffer_get_int64(&msg); 3161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_bavail = buffer_get_int64(&msg); 3171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_files = buffer_get_int64(&msg); 3181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_ffree = buffer_get_int64(&msg); 3191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_favail = buffer_get_int64(&msg); 3201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_fsid = buffer_get_int64(&msg); 3211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood flag = buffer_get_int64(&msg); 3221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_namemax = buffer_get_int64(&msg); 3231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0; 3251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0; 3261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 3281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return 0; 3301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 3311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstruct sftp_conn * 3331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests, 3341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int64_t limit_kbps) 3351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 3361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type; 3371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 3381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct sftp_conn *ret; 3391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = xmalloc(sizeof(*ret)); 3411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->fd_in = fd_in; 3421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->fd_out = fd_out; 3431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->transfer_buflen = transfer_buflen; 3441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->num_requests = num_requests; 3451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->exts = 0; 3461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->limit_kbps = 0; 3471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 3491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_INIT); 3501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, SSH2_FILEXFER_VERSION); 3511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(ret, &msg); 3521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 3541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(ret, &msg); 3561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Expecting a VERSION reply */ 3581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) { 3591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Invalid packet back from SSH2_FXP_INIT (type %u)", 3601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type); 3611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 3621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(NULL); 3631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 3641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->version = buffer_get_int(&msg); 3651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug2("Remote version: %u", ret->version); 3671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Check for extensions */ 3691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood while (buffer_len(&msg) > 0) { 3701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *name = buffer_get_string(&msg, NULL); 3711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *value = buffer_get_string(&msg, NULL); 3721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int known = 0; 3731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 3741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (strcmp(name, "posix-rename@openssh.com") == 0 && 3751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strcmp(value, "1") == 0) { 3761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->exts |= SFTP_EXT_POSIX_RENAME; 3771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood known = 1; 3781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (strcmp(name, "statvfs@openssh.com") == 0 && 3791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strcmp(value, "2") == 0) { 3801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->exts |= SFTP_EXT_STATVFS; 3811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood known = 1; 3821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (strcmp(name, "fstatvfs@openssh.com") == 0 && 3831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strcmp(value, "2") == 0) { 3841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->exts |= SFTP_EXT_FSTATVFS; 3851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood known = 1; 3861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (strcmp(name, "hardlink@openssh.com") == 0 && 3871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strcmp(value, "1") == 0) { 3881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->exts |= SFTP_EXT_HARDLINK; 3891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood known = 1; 3901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 3911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (known) { 3921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug2("Server supports extension \"%s\" revision %s", 3931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood name, value); 3941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else { 3951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug2("Unrecognised server extension \"%s\"", name); 3961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 3971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(name); 3981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(value); 3991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 4001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 4021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Some filexfer v.0 servers don't support large packets */ 4041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (ret->version == 0) 4051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->transfer_buflen = MIN(ret->transfer_buflen, 20480); 4061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->limit_kbps = limit_kbps; 4081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (ret->limit_kbps > 0) { 4091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps, 4101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->transfer_buflen); 4111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps, 4121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret->transfer_buflen); 4131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 4141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return ret; 4161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 4171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodu_int 4191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsftp_proto_version(struct sftp_conn *conn) 4201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 4211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return conn->version; 4221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 4231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 4251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_close(struct sftp_conn *conn, char *handle, u_int handle_len) 4261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 4271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id, status; 4281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 4291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 4311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 4331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_CLOSE); 4341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 4351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, handle, handle_len); 4361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 4371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message SSH2_FXP_CLOSE I:%u", id); 4381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 4401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 4411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't close file: %s", fx2txt(status)); 4421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 4441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return status; 4461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 4471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int 4501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_lsreaddir(struct sftp_conn *conn, char *path, int printflag, 4511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SFTP_DIRENT ***dir) 4521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 4531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 4541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int count, type, id, handle_len, i, expected_id, ents = 0; 4551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *handle; 4561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 4581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 4601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_OPENDIR); 4611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 4621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, path); 4631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 4641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 4661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood handle = get_handle(conn, id, &handle_len, 4681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "remote readdir(\"%s\")", path); 4691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (handle == NULL) 4701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 4711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (dir) { 4731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ents = 0; 4741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *dir = xmalloc(sizeof(**dir)); 4751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (*dir)[0] = NULL; 4761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 4771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (; !interrupted;) { 4791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = expected_id = conn->msg_id++; 4801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sending SSH2_FXP_READDIR I:%u", id); 4821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 4841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_READDIR); 4851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 4861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, handle, handle_len); 4871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 4881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 4901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 4921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 4941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 4951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received reply T:%u I:%u", type, id); 4971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 4981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 4991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("ID mismatch (%u != %u)", id, expected_id); 5001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type == SSH2_FXP_STATUS) { 5021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int status = buffer_get_int(&msg); 5031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received SSH2_FXP_STATUS %d", status); 5051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status == SSH2_FX_EOF) { 5071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood break; 5081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else { 5091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't read directory: %s", 5101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fx2txt(status)); 5111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_close(conn, handle, handle_len); 5121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(handle); 5131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 5141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (type != SSH2_FXP_NAME) 5161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 5171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_NAME, type); 5181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood count = buffer_get_int(&msg); 5201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (count == 0) 5211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood break; 5221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received %d SSH2_FXP_NAME responses", count); 5231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (i = 0; i < count; i++) { 5241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *filename, *longname; 5251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *a; 5261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood filename = buffer_get_string(&msg, NULL); 5281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood longname = buffer_get_string(&msg, NULL); 5291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a = decode_attrib(&msg); 5301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (printflag) 5321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood printf("%s\n", longname); 5331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 5351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Directory entries should never contain '/' 5361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * These can be used to attack recursive ops 5371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * (e.g. send '../../../../etc/passwd') 5381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 5391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (strchr(filename, '/') != NULL) { 5401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Server sent suspect path \"%s\" " 5411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "during readdir of \"%s\"", filename, path); 5421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood goto next; 5431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (dir) { 5461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *dir = xrealloc(*dir, ents + 2, sizeof(**dir)); 5471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (*dir)[ents] = xmalloc(sizeof(***dir)); 5481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (*dir)[ents]->filename = xstrdup(filename); 5491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (*dir)[ents]->longname = xstrdup(longname); 5501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood memcpy(&(*dir)[ents]->a, a, sizeof(*a)); 5511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (*dir)[++ents] = NULL; 5521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood next: 5541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(filename); 5551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(longname); 5561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 5601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_close(conn, handle, handle_len); 5611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(handle); 5621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Don't return partial matches on interrupt */ 5641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (interrupted && dir != NULL && *dir != NULL) { 5651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood free_sftp_dirents(*dir); 5661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood *dir = xmalloc(sizeof(**dir)); 5671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood **dir = NULL; 5681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return 0; 5711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 5721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 5741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir) 5751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 5761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(do_lsreaddir(conn, path, 0, dir)); 5771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 5781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodvoid free_sftp_dirents(SFTP_DIRENT **s) 5801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 5811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int i; 5821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (i = 0; s[i]; i++) { 5841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(s[i]->filename); 5851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(s[i]->longname); 5861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(s[i]); 5871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 5881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(s); 5891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 5901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 5921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_rm(struct sftp_conn *conn, char *path) 5931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 5941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 5951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug2("Sending SSH2_FXP_REMOVE \"%s\"", path); 5971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 5981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 5991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path)); 6001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 6011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 6021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't delete file: %s", fx2txt(status)); 6031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 6041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 6051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 6071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int printflag) 6081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 6091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 6101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 6121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path, 6131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlen(path), a); 6141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 6161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK && printflag) 6171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't create directory: %s", fx2txt(status)); 6181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 6201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 6211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 6231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_rmdir(struct sftp_conn *conn, char *path) 6241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 6251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 6261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 6281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, SSH2_FXP_RMDIR, path, 6291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlen(path)); 6301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 6321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 6331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't remove directory: %s", fx2txt(status)); 6341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 6361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 6371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6381305e95ba6ff9fa202d0818caf10405df4b0f648Mike LockwoodAttrib * 6391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_stat(struct sftp_conn *conn, char *path, int quiet) 6401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 6411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 6421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 6441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, 6461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT, 6471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood path, strlen(path)); 6481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(get_decode_stat(conn, id, quiet)); 6501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 6511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6521305e95ba6ff9fa202d0818caf10405df4b0f648Mike LockwoodAttrib * 6531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_lstat(struct sftp_conn *conn, char *path, int quiet) 6541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 6551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 6561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (conn->version == 0) { 6581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (quiet) 6591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug("Server version does not support lstat operation"); 6601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 6611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood logit("Server version does not support lstat operation"); 6621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(do_stat(conn, path, quiet)); 6631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 6641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 6661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, SSH2_FXP_LSTAT, path, 6671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlen(path)); 6681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(get_decode_stat(conn, id, quiet)); 6701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 6711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef notyet 6731305e95ba6ff9fa202d0818caf10405df4b0f648Mike LockwoodAttrib * 6741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet) 6751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 6761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 6771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 6791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, SSH2_FXP_FSTAT, handle, 6801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood handle_len); 6811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(get_decode_stat(conn, id, quiet)); 6831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 6841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif 6851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 6871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_setstat(struct sftp_conn *conn, char *path, Attrib *a) 6881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 6891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 6901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 6921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path, 6931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlen(path), a); 6941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 6951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 6961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 6971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't setstat on \"%s\": %s", path, 6981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fx2txt(status)); 6991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 7011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 7021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 7041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len, 7051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *a) 7061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 7071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 7081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 7101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle, 7111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood handle_len, a); 7121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 7141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 7151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't fsetstat: %s", fx2txt(status)); 7161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 7181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 7191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodchar * 7211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_realpath(struct sftp_conn *conn, char *path) 7221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 7231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 7241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type, expected_id, count, id; 7251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *filename, *longname; 7261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *a; 7271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood expected_id = id = conn->msg_id++; 7291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, SSH2_FXP_REALPATH, path, 7301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlen(path)); 7311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 7331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 7351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 7361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 7371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 7391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("ID mismatch (%u != %u)", id, expected_id); 7401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type == SSH2_FXP_STATUS) { 7421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status = buffer_get_int(&msg); 7431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't canonicalise: %s", fx2txt(status)); 7451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 7461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return NULL; 7471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (type != SSH2_FXP_NAME) 7481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 7491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_NAME, type); 7501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood count = buffer_get_int(&msg); 7521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (count != 1) 7531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count); 7541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood filename = buffer_get_string(&msg, NULL); 7561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood longname = buffer_get_string(&msg, NULL); 7571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a = decode_attrib(&msg); 7581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("SSH_FXP_REALPATH %s -> %s", path, filename); 7601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(longname); 7621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 7641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(filename); 7661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 7671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 7691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_rename(struct sftp_conn *conn, char *oldpath, char *newpath) 7701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 7711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 7721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 7731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 7751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send rename request */ 7771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 7781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((conn->exts & SFTP_EXT_POSIX_RENAME)) { 7791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_EXTENDED); 7801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 7811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, "posix-rename@openssh.com"); 7821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else { 7831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_RENAME); 7841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 7851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 7861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, oldpath); 7871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, newpath); 7881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 7891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message %s \"%s\" -> \"%s\"", 7901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (conn->exts & SFTP_EXT_POSIX_RENAME) ? "posix-rename@openssh.com" : 7911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "SSH2_FXP_RENAME", oldpath, newpath); 7921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 7931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 7951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 7961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath, 7971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood newpath, fx2txt(status)); 7981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 7991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 8001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 8011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 8031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath) 8041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 8051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 8061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 8071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 8091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send link request */ 8111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 8121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((conn->exts & SFTP_EXT_HARDLINK) == 0) { 8131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Server does not support hardlink@openssh.com extension"); 8141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 8151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 8161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_EXTENDED); 8181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 8191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, "hardlink@openssh.com"); 8201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, oldpath); 8211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, newpath); 8221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 8231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"", 8241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood oldpath, newpath); 8251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 8261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 8281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 8291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't link file \"%s\" to \"%s\": %s", oldpath, 8301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood newpath, fx2txt(status)); 8311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 8331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 8341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 8361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_symlink(struct sftp_conn *conn, char *oldpath, char *newpath) 8371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 8381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 8391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status, id; 8401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (conn->version < 3) { 8421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("This server does not support the symlink operation"); 8431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(SSH2_FX_OP_UNSUPPORTED); 8441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 8451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 8471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send symlink request */ 8491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 8501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_SYMLINK); 8511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 8521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, oldpath); 8531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, newpath); 8541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 8551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath, 8561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood newpath); 8571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 8581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = get_status(conn, id); 8601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) 8611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath, 8621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood newpath, fx2txt(status)); 8631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 8651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 8661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef notyet 8681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodchar * 8691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_readlink(struct sftp_conn *conn, char *path) 8701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 8711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 8721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int type, expected_id, count, id; 8731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *filename, *longname; 8741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *a; 8751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood expected_id = id = conn->msg_id++; 8771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path)); 8781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 8801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 8821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 8831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 8841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id != expected_id) 8861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("ID mismatch (%u != %u)", id, expected_id); 8871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type == SSH2_FXP_STATUS) { 8891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int status = buffer_get_int(&msg); 8901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't readlink: %s", fx2txt(status)); 8921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(NULL); 8931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (type != SSH2_FXP_NAME) 8941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_NAME(%u) packet, got %u", 8951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_NAME, type); 8961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 8971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood count = buffer_get_int(&msg); 8981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (count != 1) 8991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Got multiple names (%d) from SSH_FXP_READLINK", count); 9001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood filename = buffer_get_string(&msg, NULL); 9021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood longname = buffer_get_string(&msg, NULL); 9031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a = decode_attrib(&msg); 9041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("SSH_FXP_READLINK %s -> %s", path, filename); 9061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(longname); 9081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 9101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(filename); 9121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 9131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif 9141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 9161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st, 9171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int quiet) 9181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 9191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 9201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 9211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((conn->exts & SFTP_EXT_STATVFS) == 0) { 9231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Server does not support statvfs@openssh.com extension"); 9241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 9251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 9261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 9281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 9301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 9311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_EXTENDED); 9321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 9331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, "statvfs@openssh.com"); 9341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, path); 9351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 9361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 9371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return get_decode_statvfs(conn, st, id, quiet); 9391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 9401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef notyet 9421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 9431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len, 9441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct sftp_statvfs *st, int quiet) 9451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 9461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 9471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 9481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) { 9501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Server does not support fstatvfs@openssh.com extension"); 9511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 9521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 9531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 9551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 9571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 9581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_EXTENDED); 9591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 9601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, "fstatvfs@openssh.com"); 9611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, handle, handle_len); 9621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 9631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 9641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return get_decode_statvfs(conn, st, id, quiet); 9661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 9671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif 9681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic void 9701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodsend_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset, 9711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int len, char *handle, u_int handle_len) 9721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 9731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 9741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 9761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 9771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_READ); 9781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 9791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, handle, handle_len); 9801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int64(&msg, offset); 9811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, len); 9821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 9831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 9841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 9851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 9861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 9871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_download(struct sftp_conn *conn, char *remote_path, char *local_path, 9881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *a, int pflag) 9891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 9901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib junk; 9911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 9921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *handle; 9931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int local_fd, status = 0, write_error; 9941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int read_error, write_errno; 9951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int64_t offset, size; 9961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int handle_len, mode, type, id, buflen, num_req, max_req; 9971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood off_t progress_counter; 9981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct request { 9991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 10001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int len; 10011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int64_t offset; 10021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_ENTRY(request) tq; 10031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood }; 10041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_HEAD(reqhead, request) requests; 10051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct request *req; 10061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_INIT(&requests); 10081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL) 10101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 10111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Do not preserve set[ug]id here, as we do not preserve ownership */ 10131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 10141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood mode = a->perm & 0777; 10151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 10161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood mode = 0666; 10171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) && 10191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (!S_ISREG(a->perm))) { 10201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Cannot download non-regular file: %s", remote_path); 10211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(-1); 10221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 10231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (a->flags & SSH2_FILEXFER_ATTR_SIZE) 10251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood size = a->size; 10261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else 10271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood size = 0; 10281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buflen = conn->transfer_buflen; 10301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 10311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send open request */ 10331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 10341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_OPEN); 10351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 10361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, remote_path); 10371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, SSH2_FXF_READ); 10381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood attrib_clear(&junk); /* Send empty attributes */ 10391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood encode_attrib(&msg, &junk); 10401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 10411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 10421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood handle = get_handle(conn, id, &handle_len, 10441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "remote open(\"%s\")", remote_path); 10451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (handle == NULL) { 10461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 10471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(-1); 10481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 10491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood local_fd = open(local_path, O_WRONLY | O_CREAT | O_TRUNC, 10511b6cc98e30329f380546d5f22b1c9c975e3df4f8Mike Lockwood mode | S_IWUSR); 10521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (local_fd == -1) { 10531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't open local file \"%s\" for writing: %s", 10541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood local_path, strerror(errno)); 10551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_close(conn, handle, handle_len); 10561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 10571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(handle); 10581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(-1); 10591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 10601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Read from remote and write to local */ 10621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood write_error = read_error = write_errno = num_req = offset = 0; 10631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood max_req = 1; 10641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood progress_counter = 0; 10651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (showprogress && size != 0) 10671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood start_progress_meter(remote_path, size, &progress_counter); 10681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood while (num_req > 0 || max_req > 0) { 10701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *data; 10711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int len; 10721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 10741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Simulate EOF on interrupt: stop sending new requests and 10751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * allow outstanding requests to drain gracefully 10761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 10771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (interrupted) { 10781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (num_req == 0) /* If we haven't started yet... */ 10791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood break; 10801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood max_req = 0; 10811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 10821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 10831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send some more requests */ 10841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood while (num_req < max_req) { 10851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Request range %llu -> %llu (%d/%d)", 10861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)offset, 10871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)offset + buflen - 1, 10881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood num_req, max_req); 10891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req = xmalloc(sizeof(*req)); 10901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->id = conn->msg_id++; 10911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->len = buflen; 10921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->offset = offset; 10931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood offset += buflen; 10941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood num_req++; 10951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_INSERT_TAIL(&requests, req, tq); 10961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_read_request(conn, req->id, req->offset, 10971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->len, handle, handle_len); 10981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 10991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 11011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 11021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 11031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = buffer_get_int(&msg); 11041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received reply T:%u I:%u R:%d", type, id, max_req); 11051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Find the request in our queue */ 11071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (req = TAILQ_FIRST(&requests); 11081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req != NULL && req->id != id; 11091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req = TAILQ_NEXT(req, tq)) 11101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ; 11111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (req == NULL) 11121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Unexpected reply %u", id); 11131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood switch (type) { 11151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood case SSH2_FXP_STATUS: 11161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = buffer_get_int(&msg); 11171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_EOF) 11181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood read_error = 1; 11191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood max_req = 0; 11201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_REMOVE(&requests, req, tq); 11211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(req); 11221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood num_req--; 11231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood break; 11241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood case SSH2_FXP_DATA: 11251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood data = buffer_get_string(&msg, &len); 11261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Received data %llu -> %llu", 11271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)req->offset, 11281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)req->offset + len - 1); 11291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (len > req->len) 11301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Received more data than asked for " 11311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "%u > %u", len, req->len); 11321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((lseek(local_fd, req->offset, SEEK_SET) == -1 || 11331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood atomicio(vwrite, local_fd, data, len) != len) && 11341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood !write_error) { 11351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood write_errno = errno; 11361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood write_error = 1; 11371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood max_req = 0; 11381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 11391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood progress_counter += len; 11401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(data); 11411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (len == req->len) { 11431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_REMOVE(&requests, req, tq); 11441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(req); 11451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood num_req--; 11461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else { 11471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Resend the request for the missing data */ 11481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Short data block, re-requesting " 11491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "%llu -> %llu (%2d)", 11501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)req->offset + len, 11511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)req->offset + 11521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->len - 1, num_req); 11531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->id = conn->msg_id++; 11541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->len -= len; 11551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->offset += len; 11561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_read_request(conn, req->id, 11571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood req->offset, req->len, handle, handle_len); 11581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Reduce the request size */ 11591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (len < buflen) 11601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buflen = MAX(MIN_READ_SIZE, len); 11611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 11621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (max_req > 0) { /* max_req = 0 iff EOF received */ 11631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (size > 0 && offset > size) { 11641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Only one request at a time 11651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * after the expected EOF */ 11661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Finish at %llu (%2d)", 11671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (unsigned long long)offset, 11681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood num_req); 11691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood max_req = 1; 11701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (max_req <= conn->num_requests) { 11711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ++max_req; 11721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 11731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 11741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood break; 11751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood default: 11761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_DATA(%u) packet, got %u", 11771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SSH2_FXP_DATA, type); 11781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 11791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 11801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (showprogress && size) 11821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood stop_progress_meter(); 11831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Sanity check */ 11851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (TAILQ_FIRST(&requests) != NULL) 11861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Transfer complete, but requests still in queue"); 11871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 11881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (read_error) { 11891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't read from remote file \"%s\" : %s", 11901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood remote_path, fx2txt(status)); 11911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_close(conn, handle, handle_len); 11921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (write_error) { 11931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't write to \"%s\": %s", local_path, 11941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strerror(write_errno)); 11951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = -1; 11961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_close(conn, handle, handle_len); 11971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else { 11981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = do_close(conn, handle, handle_len); 11991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Override umask and utimes if asked */ 12011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#ifdef HAVE_FCHMOD 12021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (pflag && fchmod(local_fd, mode) == -1) 12031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#else 12041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (pflag && chmod(local_path, mode) == -1) 12051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood#endif /* HAVE_FCHMOD */ 12061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't set mode on \"%s\": %s", local_path, 12071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strerror(errno)); 12081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (pflag && (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) { 12091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct timeval tv[2]; 12101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood tv[0].tv_sec = a->atime; 12111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood tv[1].tv_sec = a->mtime; 12121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood tv[0].tv_usec = tv[1].tv_usec = 0; 12131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (utimes(local_path, tv) == -1) 12141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Can't set times on \"%s\": %s", 12151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood local_path, strerror(errno)); 12161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood close(local_fd); 12191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 12201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(handle); 12211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(status); 12231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 12241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int 12261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddownload_dir_internal(struct sftp_conn *conn, char *src, char *dst, 12271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *dirattrib, int pflag, int printflag, int depth) 12281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 12291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int i, ret = 0; 12301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood SFTP_DIRENT **dir_entries; 12311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *filename, *new_src, *new_dst; 12321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood mode_t mode = 0777; 12331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (depth >= MAX_DIR_DEPTH) { 12351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Maximum directory depth exceeded: %d levels", depth); 12361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 12371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (dirattrib == NULL && 12401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (dirattrib = do_stat(conn, src, 1)) == NULL) { 12411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Unable to stat remote directory \"%s\"", src); 12421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 12431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (!S_ISDIR(dirattrib->perm)) { 12451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("\"%s\" is not a directory", src); 12461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 12471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (printflag) 12491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood printf("Retrieving %s\n", src); 12501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) 12521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood mode = dirattrib->perm & 01777; 12531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else { 12541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug("Server did not send permissions for " 12551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "directory \"%s\"", dst); 12561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (mkdir(dst, mode) == -1 && errno != EEXIST) { 12591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("mkdir %s: %s", dst, strerror(errno)); 12601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 12611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (do_readdir(conn, src, &dir_entries) == -1) { 12641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("%s: Failed to get directory contents", src); 12651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 12661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (i = 0; dir_entries[i] != NULL && !interrupted; i++) { 12691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood filename = dir_entries[i]->filename; 12701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood new_dst = path_append(dst, filename); 12721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood new_src = path_append(src, filename); 12731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (S_ISDIR(dir_entries[i]->a.perm)) { 12751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (strcmp(filename, ".") == 0 || 12761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strcmp(filename, "..") == 0) 12771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood continue; 12781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (download_dir_internal(conn, new_src, new_dst, 12791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood &(dir_entries[i]->a), pflag, printflag, 12801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood depth + 1) == -1) 12811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = -1; 12821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (S_ISREG(dir_entries[i]->a.perm) ) { 12831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (do_download(conn, new_src, new_dst, 12841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood &(dir_entries[i]->a), pflag) == -1) { 12851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Download of file %s to %s failed", 12861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood new_src, new_dst); 12871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = -1; 12881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else 12901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood logit("%s: not a regular file\n", new_src); 12911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(new_dst); 12931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(new_src); 12941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 12951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 12961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (pflag) { 12971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) { 12981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct timeval tv[2]; 12991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood tv[0].tv_sec = dirattrib->atime; 13001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood tv[1].tv_sec = dirattrib->mtime; 13011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood tv[0].tv_usec = tv[1].tv_usec = 0; 13021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (utimes(dst, tv) == -1) 13031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Can't set times on \"%s\": %s", 13041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood dst, strerror(errno)); 13051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else 13061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug("Server did not send times for directory " 13071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "\"%s\"", dst); 13081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 13091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood free_sftp_dirents(dir_entries); 13111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return ret; 13131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 13141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 13161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddownload_dir(struct sftp_conn *conn, char *src, char *dst, 13171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib *dirattrib, int pflag, int printflag) 13181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 13191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *src_canon; 13201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int ret; 13211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((src_canon = do_realpath(conn, src)) == NULL) { 13231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Unable to canonicalise path \"%s\"", src); 13241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 13251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 13261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = download_dir_internal(conn, src_canon, dst, 13281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood dirattrib, pflag, printflag, 0); 13291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(src_canon); 13301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return ret; 13311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 13321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 13341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwooddo_upload(struct sftp_conn *conn, char *local_path, char *remote_path, 13351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int pflag) 13361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 13371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int local_fd; 13381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int status = SSH2_FX_OK; 13391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int handle_len, id, type; 13401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood off_t offset; 13411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *handle, *data; 13421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Buffer msg; 13431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct stat sb; 13441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib a; 13451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int32_t startid; 13461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int32_t ackid; 13471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct outstanding_ack { 13481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int id; 13491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int len; 13501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood off_t offset; 13511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_ENTRY(outstanding_ack) tq; 13521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood }; 13531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_HEAD(ackhead, outstanding_ack) acks; 13541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct outstanding_ack *ack = NULL; 13551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_INIT(&acks); 13571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) { 13591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't open local file \"%s\" for reading: %s", 13601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood local_path, strerror(errno)); 13611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(-1); 13621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 13631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (fstat(local_fd, &sb) == -1) { 13641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't fstat local file \"%s\": %s", 13651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood local_path, strerror(errno)); 13661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood close(local_fd); 13671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(-1); 13681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 13691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (!S_ISREG(sb.st_mode)) { 13701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("%s is not a regular file", local_path); 13711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood close(local_fd); 13721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(-1); 13731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 13741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood stat_to_attrib(&sb, &a); 13751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 13771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 13781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.perm &= 0777; 13791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (!pflag) 13801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 13811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_init(&msg); 13831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Send open request */ 13851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id = conn->msg_id++; 13861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_OPEN); 13871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, id); 13881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_cstring(&msg, remote_path); 13891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC); 13901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood encode_attrib(&msg, &a); 13911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 13921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path); 13931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 13951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 13961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood handle = get_handle(conn, id, &handle_len, 13971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "remote open(\"%s\")", remote_path); 13981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (handle == NULL) { 13991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood close(local_fd); 14001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 14011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 14021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 14031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood startid = ackid = id + 1; 14051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood data = xmalloc(conn->transfer_buflen); 14061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Read from local and write to remote */ 14081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood offset = 0; 14091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (showprogress) 14101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood start_progress_meter(local_path, sb.st_size, &offset); 14111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (;;) { 14131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int len; 14141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 14161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Can't use atomicio here because it returns 0 on EOF, 14171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * thus losing the last block of the file. 14181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * Simulate an EOF on interrupt, allowing ACKs from the 14191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * server to drain. 14201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 14211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (interrupted || status != SSH2_FX_OK) 14221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood len = 0; 14231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood else do 14241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood len = read(local_fd, data, conn->transfer_buflen); 14251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood while ((len == -1) && 14261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK)); 14271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (len == -1) 14291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Couldn't read from \"%s\": %s", local_path, 14301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strerror(errno)); 14311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (len != 0) { 14331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack = xmalloc(sizeof(*ack)); 14341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack->id = ++id; 14351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack->offset = offset; 14361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack->len = len; 14371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_INSERT_TAIL(&acks, ack, tq); 14381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 14401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_char(&msg, SSH2_FXP_WRITE); 14411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int(&msg, ack->id); 14421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, handle, handle_len); 14431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_int64(&msg, offset); 14441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_put_string(&msg, data, len); 14451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood send_msg(conn, &msg); 14461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u", 14471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id, (unsigned long long)offset, len); 14481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (TAILQ_FIRST(&acks) == NULL) 14491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood break; 14501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (ack == NULL) 14521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Unexpected ACK %u", id); 14531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (id == startid || len == 0 || 14551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood id - ackid >= conn->num_requests) { 14561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood u_int r_id; 14571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_clear(&msg); 14591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood get_msg(conn, &msg); 14601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood type = buffer_get_char(&msg); 14611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood r_id = buffer_get_int(&msg); 14621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (type != SSH2_FXP_STATUS) 14641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Expected SSH2_FXP_STATUS(%d) packet, " 14651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood "got %d", SSH2_FXP_STATUS, type); 14661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = buffer_get_int(&msg); 14681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("SSH2_FXP_STATUS %d", status); 14691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Find the request in our queue */ 14711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood for (ack = TAILQ_FIRST(&acks); 14721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack != NULL && ack->id != r_id; 14731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack = TAILQ_NEXT(ack, tq)) 14741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ; 14751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (ack == NULL) 14761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("Can't find request for ID %u", r_id); 14771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood TAILQ_REMOVE(&acks, ack, tq); 14781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood debug3("In write loop, ack for %u %u bytes at %lld", 14791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ack->id, ack->len, (long long)ack->offset); 14801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ++ackid; 14811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(ack); 14821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 14831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood offset += len; 14841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (offset < 0) 14851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood fatal("%s: offset < 0", __func__); 14861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 14871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood buffer_free(&msg); 14881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (showprogress) 14901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood stop_progress_meter(); 14911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(data); 14921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) { 14941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't write to remote file \"%s\": %s", 14951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood remote_path, fx2txt(status)); 14961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = -1; 14971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 14981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 14991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (close(local_fd) == -1) { 15001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't close local file \"%s\": %s", local_path, 15011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strerror(errno)); 15021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = -1; 15031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* Override umask and utimes if asked */ 15061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (pflag) 15071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_fsetstat(conn, handle, handle_len, &a); 15081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (do_close(conn, handle, handle_len) != SSH2_FX_OK) 15101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = -1; 15111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(handle); 15121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return status; 15141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 15151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodstatic int 15171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodupload_dir_internal(struct sftp_conn *conn, char *src, char *dst, 15181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int pflag, int printflag, int depth) 15191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 15201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int ret = 0, status; 15211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood DIR *dirp; 15221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct dirent *dp; 15231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *filename, *new_src, *new_dst; 15241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood struct stat sb; 15251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood Attrib a; 15261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (depth >= MAX_DIR_DEPTH) { 15281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Maximum directory depth exceeded: %d levels", depth); 15291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 15301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (stat(src, &sb) == -1) { 15331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Couldn't stat directory \"%s\": %s", 15341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood src, strerror(errno)); 15351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 15361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (!S_ISDIR(sb.st_mode)) { 15381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("\"%s\" is not a directory", src); 15391305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 15401305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15411305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (printflag) 15421305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood printf("Entering %s\n", src); 15431305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15441305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood attrib_clear(&a); 15451305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood stat_to_attrib(&sb, &a); 15461305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.flags &= ~SSH2_FILEXFER_ATTR_SIZE; 15471305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID; 15481305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.perm &= 01777; 15491305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (!pflag) 15501305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME; 15511305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15521305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood status = do_mkdir(conn, dst, &a, 0); 15531305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood /* 15541305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * we lack a portable status for errno EEXIST, 15551305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * so if we get a SSH2_FX_FAILURE back we must check 15561305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood * if it was created successfully. 15571305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood */ 15581305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_OK) { 15591305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (status != SSH2_FX_FAILURE) 15601305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 15611305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (do_stat(conn, dst, 0) == NULL) 15621305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 15631305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15641305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15651305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((dirp = opendir(src)) == NULL) { 15661305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Failed to open dir \"%s\": %s", src, strerror(errno)); 15671305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 15681305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15691305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15701305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood while (((dp = readdir(dirp)) != NULL) && !interrupted) { 15711305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (dp->d_ino == 0) 15721305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood continue; 15731305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood filename = dp->d_name; 15741305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood new_dst = path_append(dst, filename); 15751305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood new_src = path_append(src, filename); 15761305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15771305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (lstat(new_src, &sb) == -1) { 15781305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood logit("%s: lstat failed: %s", filename, 15791305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strerror(errno)); 15801305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = -1; 15811305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (S_ISDIR(sb.st_mode)) { 15821305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (strcmp(filename, ".") == 0 || 15831305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strcmp(filename, "..") == 0) 15841305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood continue; 15851305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 15861305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (upload_dir_internal(conn, new_src, new_dst, 15871305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood pflag, printflag, depth + 1) == -1) 15881305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = -1; 15891305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else if (S_ISREG(sb.st_mode)) { 15901305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (do_upload(conn, new_src, new_dst, pflag) == -1) { 15911305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Uploading of file %s to %s failed!", 15921305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood new_src, new_dst); 15931305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = -1; 15941305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 15951305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } else 15961305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood logit("%s: not a regular file\n", filename); 15971305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(new_dst); 15981305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(new_src); 15991305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 16001305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16011305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood do_setstat(conn, dst, &a); 16021305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16031305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood (void) closedir(dirp); 16041305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return ret; 16051305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 16061305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16071305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodint 16081305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodupload_dir(struct sftp_conn *conn, char *src, char *dst, int printflag, 16091305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int pflag) 16101305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 16111305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *dst_canon; 16121305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood int ret; 16131305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16141305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if ((dst_canon = do_realpath(conn, dst)) == NULL) { 16151305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood error("Unable to canonicalise path \"%s\"", dst); 16161305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return -1; 16171305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood } 16181305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16191305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = upload_dir_internal(conn, src, dst_canon, pflag, printflag, 0); 16201305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood xfree(dst_canon); 16211305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return ret; 16221305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 16231305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16241305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodchar * 16251305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwoodpath_append(char *p1, char *p2) 16261305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood{ 16271305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood char *ret; 16281305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood size_t len = strlen(p1) + strlen(p2) + 2; 16291305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16301305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood ret = xmalloc(len); 16311305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlcpy(ret, p1, len); 16321305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/') 16331305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlcat(ret, "/", len); 16341305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood strlcat(ret, p2, len); 16351305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 16361305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood return(ret); 16371305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood} 16381305e95ba6ff9fa202d0818caf10405df4b0f648Mike Lockwood 1639