LCOV - code coverage report
Current view: top level - openssh-6.6p1 - sftp-client.c (source / functions) Hit Total Coverage
Test: lcov_coverage_final.info Lines: 606 871 69.6 %
Date: 2014-08-01 Functions: 29 36 80.6 %
Branches: 199 453 43.9 %

           Branch data     Line data    Source code
       1                 :            : /* $OpenBSD: sftp-client.c,v 1.114 2014/01/31 16:39:19 tedu Exp $ */
       2                 :            : /*
       3                 :            :  * Copyright (c) 2001-2004 Damien Miller <djm@openbsd.org>
       4                 :            :  *
       5                 :            :  * Permission to use, copy, modify, and distribute this software for any
       6                 :            :  * purpose with or without fee is hereby granted, provided that the above
       7                 :            :  * copyright notice and this permission notice appear in all copies.
       8                 :            :  *
       9                 :            :  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      10                 :            :  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
      11                 :            :  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
      12                 :            :  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
      13                 :            :  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
      14                 :            :  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
      15                 :            :  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
      16                 :            :  */
      17                 :            : 
      18                 :            : /* XXX: memleaks */
      19                 :            : /* XXX: signed vs unsigned */
      20                 :            : /* XXX: remove all logging, only return status codes */
      21                 :            : /* XXX: copy between two remote sites */
      22                 :            : 
      23                 :            : #include "includes.h"
      24                 :            : 
      25                 :            : #include <sys/types.h>
      26                 :            : #include <sys/param.h>
      27                 :            : #ifdef HAVE_SYS_STATVFS_H
      28                 :            : #include <sys/statvfs.h>
      29                 :            : #endif
      30                 :            : #include "openbsd-compat/sys-queue.h"
      31                 :            : #ifdef HAVE_SYS_STAT_H
      32                 :            : # include <sys/stat.h>
      33                 :            : #endif
      34                 :            : #ifdef HAVE_SYS_TIME_H
      35                 :            : # include <sys/time.h>
      36                 :            : #endif
      37                 :            : #include <sys/uio.h>
      38                 :            : 
      39                 :            : #include <dirent.h>
      40                 :            : #include <errno.h>
      41                 :            : #include <fcntl.h>
      42                 :            : #include <signal.h>
      43                 :            : #include <stdarg.h>
      44                 :            : #include <stdio.h>
      45                 :            : #include <stdlib.h>
      46                 :            : #include <string.h>
      47                 :            : #include <unistd.h>
      48                 :            : 
      49                 :            : #include "xmalloc.h"
      50                 :            : #include "buffer.h"
      51                 :            : #include "log.h"
      52                 :            : #include "atomicio.h"
      53                 :            : #include "progressmeter.h"
      54                 :            : #include "misc.h"
      55                 :            : 
      56                 :            : #include "sftp.h"
      57                 :            : #include "sftp-common.h"
      58                 :            : #include "sftp-client.h"
      59                 :            : 
      60                 :            : extern volatile sig_atomic_t interrupted;
      61                 :            : extern int showprogress;
      62                 :            : 
      63                 :            : /* Minimum amount of data to read at a time */
      64                 :            : #define MIN_READ_SIZE   512
      65                 :            : 
      66                 :            : /* Maximum depth to descend in directory trees */
      67                 :            : #define MAX_DIR_DEPTH 64
      68                 :            : 
      69                 :            : struct sftp_conn {
      70                 :            :         int fd_in;
      71                 :            :         int fd_out;
      72                 :            :         u_int transfer_buflen;
      73                 :            :         u_int num_requests;
      74                 :            :         u_int version;
      75                 :            :         u_int msg_id;
      76                 :            : #define SFTP_EXT_POSIX_RENAME   0x00000001
      77                 :            : #define SFTP_EXT_STATVFS        0x00000002
      78                 :            : #define SFTP_EXT_FSTATVFS       0x00000004
      79                 :            : #define SFTP_EXT_HARDLINK       0x00000008
      80                 :            : #define SFTP_EXT_FSYNC          0x00000010
      81                 :            :         u_int exts;
      82                 :            :         u_int64_t limit_kbps;
      83                 :            :         struct bwlimit bwlimit_in, bwlimit_out;
      84                 :            : };
      85                 :            : 
      86                 :            : static char *
      87                 :            : get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len,
      88                 :            :     const char *errfmt, ...) __attribute__((format(printf, 4, 5)));
      89                 :            : 
      90                 :            : /* ARGSUSED */
      91                 :            : static int
      92                 :          0 : sftpio(void *_bwlimit, size_t amount)
      93                 :            : {
      94                 :          0 :         struct bwlimit *bwlimit = (struct bwlimit *)_bwlimit;
      95                 :            : 
      96                 :          0 :         bandwidth_limit(bwlimit, amount);
      97                 :          0 :         return 0;
      98                 :            : }
      99                 :            : 
     100                 :            : static void
     101                 :    1416773 : send_msg(struct sftp_conn *conn, Buffer *m)
     102                 :            : {
     103                 :            :         u_char mlen[4];
     104                 :            :         struct iovec iov[2];
     105                 :            : 
     106         [ -  + ]:    1416773 :         if (buffer_len(m) > SFTP_MAX_MSG_LENGTH)
     107                 :          0 :                 fatal("Outbound message too long %u", buffer_len(m));
     108                 :            : 
     109                 :            :         /* Send length first */
     110                 :    1416773 :         put_u32(mlen, buffer_len(m));
     111                 :    1416773 :         iov[0].iov_base = mlen;
     112                 :    1416773 :         iov[0].iov_len = sizeof(mlen);
     113                 :    1416773 :         iov[1].iov_base = buffer_ptr(m);
     114                 :    1416773 :         iov[1].iov_len = buffer_len(m);
     115                 :            : 
     116 [ +  - ][ -  + ]:    2833546 :         if (atomiciov6(writev, conn->fd_out, iov, 2,
     117                 :    1416773 :             conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_out) !=
     118                 :    1416773 :             buffer_len(m) + sizeof(mlen))
     119                 :          0 :                 fatal("Couldn't send packet: %s", strerror(errno));
     120                 :            : 
     121                 :    1416773 :         buffer_clear(m);
     122                 :    1416773 : }
     123                 :            : 
     124                 :            : static void
     125                 :    1416773 : get_msg(struct sftp_conn *conn, Buffer *m)
     126                 :            : {
     127                 :            :         u_int msg_len;
     128                 :            : 
     129                 :    1416773 :         buffer_append_space(m, 4);
     130 [ +  - ][ -  + ]:    1416773 :         if (atomicio6(read, conn->fd_in, buffer_ptr(m), 4,
     131                 :    1416773 :             conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in) != 4) {
     132         [ #  # ]:          0 :                 if (errno == EPIPE)
     133                 :          0 :                         fatal("Connection closed");
     134                 :            :                 else
     135                 :          0 :                         fatal("Couldn't read packet: %s", strerror(errno));
     136                 :            :         }
     137                 :            : 
     138                 :    1416773 :         msg_len = buffer_get_int(m);
     139         [ -  + ]:    1416773 :         if (msg_len > SFTP_MAX_MSG_LENGTH)
     140                 :          0 :                 fatal("Received message too long %u", msg_len);
     141                 :            : 
     142                 :    1416773 :         buffer_append_space(m, msg_len);
     143 [ +  - ][ -  + ]:    1416773 :         if (atomicio6(read, conn->fd_in, buffer_ptr(m), msg_len,
     144                 :    1416773 :             conn->limit_kbps > 0 ? sftpio : NULL, &conn->bwlimit_in)
     145                 :            :             != msg_len) {
     146         [ #  # ]:          0 :                 if (errno == EPIPE)
     147                 :          0 :                         fatal("Connection closed");
     148                 :            :                 else
     149                 :          0 :                         fatal("Read packet: %s", strerror(errno));
     150                 :            :         }
     151                 :    1416773 : }
     152                 :            : 
     153                 :            : static void
     154                 :        379 : send_string_request(struct sftp_conn *conn, u_int id, u_int code, char *s,
     155                 :            :     u_int len)
     156                 :            : {
     157                 :            :         Buffer msg;
     158                 :            : 
     159                 :        379 :         buffer_init(&msg);
     160                 :        379 :         buffer_put_char(&msg, code);
     161                 :        379 :         buffer_put_int(&msg, id);
     162                 :        379 :         buffer_put_string(&msg, s, len);
     163                 :        379 :         send_msg(conn, &msg);
     164                 :        379 :         debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
     165                 :        379 :         buffer_free(&msg);
     166                 :        379 : }
     167                 :            : 
     168                 :            : static void
     169                 :         13 : send_string_attrs_request(struct sftp_conn *conn, u_int id, u_int code,
     170                 :            :     char *s, u_int len, Attrib *a)
     171                 :            : {
     172                 :            :         Buffer msg;
     173                 :            : 
     174                 :         13 :         buffer_init(&msg);
     175                 :         13 :         buffer_put_char(&msg, code);
     176                 :         13 :         buffer_put_int(&msg, id);
     177                 :         13 :         buffer_put_string(&msg, s, len);
     178                 :         13 :         encode_attrib(&msg, a);
     179                 :         13 :         send_msg(conn, &msg);
     180                 :         13 :         debug3("Sent message fd %d T:%u I:%u", conn->fd_out, code, id);
     181                 :         13 :         buffer_free(&msg);
     182                 :         13 : }
     183                 :            : 
     184                 :            : static u_int
     185                 :        158 : get_status(struct sftp_conn *conn, u_int expected_id)
     186                 :            : {
     187                 :            :         Buffer msg;
     188                 :            :         u_int type, id, status;
     189                 :            : 
     190                 :        158 :         buffer_init(&msg);
     191                 :        158 :         get_msg(conn, &msg);
     192                 :        158 :         type = buffer_get_char(&msg);
     193                 :        158 :         id = buffer_get_int(&msg);
     194                 :            : 
     195         [ -  + ]:        158 :         if (id != expected_id)
     196                 :          0 :                 fatal("ID mismatch (%u != %u)", id, expected_id);
     197         [ -  + ]:        158 :         if (type != SSH2_FXP_STATUS)
     198                 :          0 :                 fatal("Expected SSH2_FXP_STATUS(%u) packet, got %u",
     199                 :            :                     SSH2_FXP_STATUS, type);
     200                 :            : 
     201                 :        158 :         status = buffer_get_int(&msg);
     202                 :        158 :         buffer_free(&msg);
     203                 :            : 
     204                 :        158 :         debug3("SSH2_FXP_STATUS %u", status);
     205                 :            : 
     206                 :        158 :         return status;
     207                 :            : }
     208                 :            : 
     209                 :            : static char *
     210                 :        104 : get_handle(struct sftp_conn *conn, u_int expected_id, u_int *len,
     211                 :            :     const char *errfmt, ...)
     212                 :            : {
     213                 :            :         Buffer msg;
     214                 :            :         u_int type, id;
     215                 :            :         char *handle, errmsg[256];
     216                 :            :         va_list args;
     217                 :            :         int status;
     218                 :            : 
     219                 :        104 :         va_start(args, errfmt);
     220         [ +  - ]:        104 :         if (errfmt != NULL)
     221                 :            :                 vsnprintf(errmsg, sizeof(errmsg), errfmt, args);
     222                 :        104 :         va_end(args);
     223                 :            : 
     224                 :        104 :         buffer_init(&msg);
     225                 :        104 :         get_msg(conn, &msg);
     226                 :        104 :         type = buffer_get_char(&msg);
     227                 :        104 :         id = buffer_get_int(&msg);
     228                 :            : 
     229         [ -  + ]:        104 :         if (id != expected_id)
     230         [ #  # ]:          0 :                 fatal("%s: ID mismatch (%u != %u)",
     231                 :            :                     errfmt == NULL ? __func__ : errmsg, id, expected_id);
     232         [ +  + ]:        104 :         if (type == SSH2_FXP_STATUS) {
     233                 :          5 :                 status = buffer_get_int(&msg);
     234         [ +  - ]:          5 :                 if (errfmt != NULL)
     235                 :          5 :                         error("%s: %s", errmsg, fx2txt(status));
     236                 :          5 :                 buffer_free(&msg);
     237                 :          5 :                 return(NULL);
     238         [ -  + ]:         99 :         } else if (type != SSH2_FXP_HANDLE)
     239         [ #  # ]:          0 :                 fatal("%s: Expected SSH2_FXP_HANDLE(%u) packet, got %u",
     240                 :            :                     errfmt == NULL ? __func__ : errmsg, SSH2_FXP_HANDLE, type);
     241                 :            : 
     242                 :         99 :         handle = buffer_get_string(&msg, len);
     243                 :         99 :         buffer_free(&msg);
     244                 :            : 
     245                 :         99 :         return(handle);
     246                 :            : }
     247                 :            : 
     248                 :            : static Attrib *
     249                 :        210 : get_decode_stat(struct sftp_conn *conn, u_int expected_id, int quiet)
     250                 :            : {
     251                 :            :         Buffer msg;
     252                 :            :         u_int type, id;
     253                 :            :         Attrib *a;
     254                 :            : 
     255                 :        210 :         buffer_init(&msg);
     256                 :        210 :         get_msg(conn, &msg);
     257                 :            : 
     258                 :        210 :         type = buffer_get_char(&msg);
     259                 :        210 :         id = buffer_get_int(&msg);
     260                 :            : 
     261                 :        210 :         debug3("Received stat reply T:%u I:%u", type, id);
     262         [ -  + ]:        210 :         if (id != expected_id)
     263                 :          0 :                 fatal("ID mismatch (%u != %u)", id, expected_id);
     264         [ +  + ]:        210 :         if (type == SSH2_FXP_STATUS) {
     265                 :         30 :                 int status = buffer_get_int(&msg);
     266                 :            : 
     267         [ +  - ]:         30 :                 if (quiet)
     268                 :         30 :                         debug("Couldn't stat remote file: %s", fx2txt(status));
     269                 :            :                 else
     270                 :          0 :                         error("Couldn't stat remote file: %s", fx2txt(status));
     271                 :         30 :                 buffer_free(&msg);
     272                 :         30 :                 return(NULL);
     273         [ -  + ]:        180 :         } else if (type != SSH2_FXP_ATTRS) {
     274                 :          0 :                 fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
     275                 :            :                     SSH2_FXP_ATTRS, type);
     276                 :            :         }
     277                 :        180 :         a = decode_attrib(&msg);
     278                 :        180 :         buffer_free(&msg);
     279                 :            : 
     280                 :        180 :         return(a);
     281                 :            : }
     282                 :            : 
     283                 :            : static int
     284                 :          4 : get_decode_statvfs(struct sftp_conn *conn, struct sftp_statvfs *st,
     285                 :            :     u_int expected_id, int quiet)
     286                 :            : {
     287                 :            :         Buffer msg;
     288                 :            :         u_int type, id, flag;
     289                 :            : 
     290                 :          4 :         buffer_init(&msg);
     291                 :          4 :         get_msg(conn, &msg);
     292                 :            : 
     293                 :          4 :         type = buffer_get_char(&msg);
     294                 :          4 :         id = buffer_get_int(&msg);
     295                 :            : 
     296                 :          4 :         debug3("Received statvfs reply T:%u I:%u", type, id);
     297         [ -  + ]:          4 :         if (id != expected_id)
     298                 :          0 :                 fatal("ID mismatch (%u != %u)", id, expected_id);
     299         [ +  + ]:          4 :         if (type == SSH2_FXP_STATUS) {
     300                 :          2 :                 int status = buffer_get_int(&msg);
     301                 :            : 
     302         [ +  - ]:          2 :                 if (quiet)
     303                 :          2 :                         debug("Couldn't statvfs: %s", fx2txt(status));
     304                 :            :                 else
     305                 :          0 :                         error("Couldn't statvfs: %s", fx2txt(status));
     306                 :          2 :                 buffer_free(&msg);
     307                 :          2 :                 return -1;
     308         [ -  + ]:          2 :         } else if (type != SSH2_FXP_EXTENDED_REPLY) {
     309                 :          0 :                 fatal("Expected SSH2_FXP_EXTENDED_REPLY(%u) packet, got %u",
     310                 :            :                     SSH2_FXP_EXTENDED_REPLY, type);
     311                 :            :         }
     312                 :            : 
     313                 :            :         memset(st, 0, sizeof(*st));
     314                 :          2 :         st->f_bsize = buffer_get_int64(&msg);
     315                 :          2 :         st->f_frsize = buffer_get_int64(&msg);
     316                 :          2 :         st->f_blocks = buffer_get_int64(&msg);
     317                 :          2 :         st->f_bfree = buffer_get_int64(&msg);
     318                 :          2 :         st->f_bavail = buffer_get_int64(&msg);
     319                 :          2 :         st->f_files = buffer_get_int64(&msg);
     320                 :          2 :         st->f_ffree = buffer_get_int64(&msg);
     321                 :          2 :         st->f_favail = buffer_get_int64(&msg);
     322                 :          2 :         st->f_fsid = buffer_get_int64(&msg);
     323                 :          2 :         flag = buffer_get_int64(&msg);
     324                 :          2 :         st->f_namemax = buffer_get_int64(&msg);
     325                 :            : 
     326                 :          2 :         st->f_flag = (flag & SSH2_FXE_STATVFS_ST_RDONLY) ? ST_RDONLY : 0;
     327                 :          2 :         st->f_flag |= (flag & SSH2_FXE_STATVFS_ST_NOSUID) ? ST_NOSUID : 0;
     328                 :            : 
     329                 :          2 :         buffer_free(&msg);
     330                 :            : 
     331                 :          2 :         return 0;
     332                 :            : }
     333                 :            : 
     334                 :            : struct sftp_conn *
     335                 :        150 : do_init(int fd_in, int fd_out, u_int transfer_buflen, u_int num_requests,
     336                 :            :     u_int64_t limit_kbps)
     337                 :            : {
     338                 :            :         u_int type;
     339                 :            :         Buffer msg;
     340                 :            :         struct sftp_conn *ret;
     341                 :            : 
     342                 :        150 :         ret = xcalloc(1, sizeof(*ret));
     343                 :        150 :         ret->msg_id = 1;
     344                 :        150 :         ret->fd_in = fd_in;
     345                 :        150 :         ret->fd_out = fd_out;
     346                 :        150 :         ret->transfer_buflen = transfer_buflen;
     347                 :        150 :         ret->num_requests = num_requests;
     348                 :        150 :         ret->exts = 0;
     349                 :        150 :         ret->limit_kbps = 0;
     350                 :            : 
     351                 :        150 :         buffer_init(&msg);
     352                 :        150 :         buffer_put_char(&msg, SSH2_FXP_INIT);
     353                 :        150 :         buffer_put_int(&msg, SSH2_FILEXFER_VERSION);
     354                 :        150 :         send_msg(ret, &msg);
     355                 :            : 
     356                 :        150 :         buffer_clear(&msg);
     357                 :            : 
     358                 :        150 :         get_msg(ret, &msg);
     359                 :            : 
     360                 :            :         /* Expecting a VERSION reply */
     361         [ -  + ]:        150 :         if ((type = buffer_get_char(&msg)) != SSH2_FXP_VERSION) {
     362                 :          0 :                 error("Invalid packet back from SSH2_FXP_INIT (type %u)",
     363                 :            :                     type);
     364                 :          0 :                 buffer_free(&msg);
     365                 :          0 :                 return(NULL);
     366                 :            :         }
     367                 :        150 :         ret->version = buffer_get_int(&msg);
     368                 :            : 
     369                 :        150 :         debug2("Remote version: %u", ret->version);
     370                 :            : 
     371                 :            :         /* Check for extensions */
     372         [ +  + ]:        900 :         while (buffer_len(&msg) > 0) {
     373                 :        750 :                 char *name = buffer_get_string(&msg, NULL);
     374                 :        750 :                 char *value = buffer_get_string(&msg, NULL);
     375                 :        750 :                 int known = 0;
     376                 :            : 
     377 [ +  + ][ +  - ]:        900 :                 if (strcmp(name, "posix-rename@openssh.com") == 0 &&
     378         [ +  - ]:        150 :                     strcmp(value, "1") == 0) {
     379                 :        150 :                         ret->exts |= SFTP_EXT_POSIX_RENAME;
     380                 :        150 :                         known = 1;
     381 [ +  + ][ +  - ]:        750 :                 } else if (strcmp(name, "statvfs@openssh.com") == 0 &&
     382         [ +  - ]:        150 :                     strcmp(value, "2") == 0) {
     383                 :        150 :                         ret->exts |= SFTP_EXT_STATVFS;
     384                 :        150 :                         known = 1;
     385 [ +  + ][ +  - ]:        600 :                 } else if (strcmp(name, "fstatvfs@openssh.com") == 0 &&
     386         [ +  - ]:        150 :                     strcmp(value, "2") == 0) {
     387                 :        150 :                         ret->exts |= SFTP_EXT_FSTATVFS;
     388                 :        150 :                         known = 1;
     389 [ +  + ][ +  - ]:        450 :                 } else if (strcmp(name, "hardlink@openssh.com") == 0 &&
     390         [ +  - ]:        150 :                     strcmp(value, "1") == 0) {
     391                 :        150 :                         ret->exts |= SFTP_EXT_HARDLINK;
     392                 :        150 :                         known = 1;
     393 [ +  - ][ +  - ]:        300 :                 } else if (strcmp(name, "fsync@openssh.com") == 0 &&
     394         [ +  - ]:        150 :                     strcmp(value, "1") == 0) {
     395                 :        150 :                         ret->exts |= SFTP_EXT_FSYNC;
     396                 :        150 :                         known = 1;
     397                 :            :                 }
     398         [ +  - ]:        750 :                 if (known) {
     399                 :        750 :                         debug2("Server supports extension \"%s\" revision %s",
     400                 :            :                             name, value);
     401                 :            :                 } else {
     402                 :          0 :                         debug2("Unrecognised server extension \"%s\"", name);
     403                 :            :                 }
     404                 :        750 :                 free(name);
     405                 :        750 :                 free(value);
     406                 :            :         }
     407                 :            : 
     408                 :        150 :         buffer_free(&msg);
     409                 :            : 
     410                 :            :         /* Some filexfer v.0 servers don't support large packets */
     411         [ -  + ]:        150 :         if (ret->version == 0)
     412                 :          0 :                 ret->transfer_buflen = MIN(ret->transfer_buflen, 20480);
     413                 :            : 
     414                 :        150 :         ret->limit_kbps = limit_kbps;
     415         [ -  + ]:        150 :         if (ret->limit_kbps > 0) {
     416                 :          0 :                 bandwidth_limit_init(&ret->bwlimit_in, ret->limit_kbps,
     417                 :          0 :                     ret->transfer_buflen);
     418                 :          0 :                 bandwidth_limit_init(&ret->bwlimit_out, ret->limit_kbps,
     419                 :          0 :                     ret->transfer_buflen);
     420                 :            :         }
     421                 :            : 
     422                 :        150 :         return ret;
     423                 :            : }
     424                 :            : 
     425                 :            : u_int
     426                 :         12 : sftp_proto_version(struct sftp_conn *conn)
     427                 :            : {
     428                 :         12 :         return conn->version;
     429                 :            : }
     430                 :            : 
     431                 :            : int
     432                 :         99 : do_close(struct sftp_conn *conn, char *handle, u_int handle_len)
     433                 :            : {
     434                 :            :         u_int id, status;
     435                 :            :         Buffer msg;
     436                 :            : 
     437                 :         99 :         buffer_init(&msg);
     438                 :            : 
     439                 :         99 :         id = conn->msg_id++;
     440                 :         99 :         buffer_put_char(&msg, SSH2_FXP_CLOSE);
     441                 :         99 :         buffer_put_int(&msg, id);
     442                 :         99 :         buffer_put_string(&msg, handle, handle_len);
     443                 :         99 :         send_msg(conn, &msg);
     444                 :         99 :         debug3("Sent message SSH2_FXP_CLOSE I:%u", id);
     445                 :            : 
     446                 :         99 :         status = get_status(conn, id);
     447         [ +  + ]:         99 :         if (status != SSH2_FX_OK)
     448                 :          3 :                 error("Couldn't close file: %s", fx2txt(status));
     449                 :            : 
     450                 :         99 :         buffer_free(&msg);
     451                 :            : 
     452                 :         99 :         return status;
     453                 :            : }
     454                 :            : 
     455                 :            : 
     456                 :            : static int
     457                 :         17 : do_lsreaddir(struct sftp_conn *conn, char *path, int print_flag,
     458                 :            :     SFTP_DIRENT ***dir)
     459                 :            : {
     460                 :            :         Buffer msg;
     461                 :         17 :         u_int count, type, id, handle_len, i, expected_id, ents = 0;
     462                 :            :         char *handle;
     463                 :         17 :         int status = SSH2_FX_FAILURE;
     464                 :            : 
     465         [ +  - ]:         17 :         if (dir)
     466                 :         17 :                 *dir = NULL;
     467                 :            : 
     468                 :         17 :         id = conn->msg_id++;
     469                 :            : 
     470                 :         17 :         buffer_init(&msg);
     471                 :         17 :         buffer_put_char(&msg, SSH2_FXP_OPENDIR);
     472                 :         17 :         buffer_put_int(&msg, id);
     473                 :         17 :         buffer_put_cstring(&msg, path);
     474                 :         17 :         send_msg(conn, &msg);
     475                 :            : 
     476                 :         17 :         handle = get_handle(conn, id, &handle_len,
     477                 :            :             "remote readdir(\"%s\")", path);
     478         [ +  + ]:         17 :         if (handle == NULL) {
     479                 :          2 :                 buffer_free(&msg);
     480                 :          2 :                 return -1;
     481                 :            :         }
     482                 :            : 
     483         [ +  - ]:         15 :         if (dir) {
     484                 :         15 :                 ents = 0;
     485                 :         15 :                 *dir = xcalloc(1, sizeof(**dir));
     486                 :         15 :                 (*dir)[0] = NULL;
     487                 :            :         }
     488                 :            : 
     489         [ +  - ]:         38 :         for (; !interrupted;) {
     490                 :         38 :                 id = expected_id = conn->msg_id++;
     491                 :            : 
     492                 :         38 :                 debug3("Sending SSH2_FXP_READDIR I:%u", id);
     493                 :            : 
     494                 :         38 :                 buffer_clear(&msg);
     495                 :         38 :                 buffer_put_char(&msg, SSH2_FXP_READDIR);
     496                 :         38 :                 buffer_put_int(&msg, id);
     497                 :         38 :                 buffer_put_string(&msg, handle, handle_len);
     498                 :         38 :                 send_msg(conn, &msg);
     499                 :            : 
     500                 :         38 :                 buffer_clear(&msg);
     501                 :            : 
     502                 :         38 :                 get_msg(conn, &msg);
     503                 :            : 
     504                 :         38 :                 type = buffer_get_char(&msg);
     505                 :         38 :                 id = buffer_get_int(&msg);
     506                 :            : 
     507                 :         38 :                 debug3("Received reply T:%u I:%u", type, id);
     508                 :            : 
     509         [ -  + ]:         38 :                 if (id != expected_id)
     510                 :          0 :                         fatal("ID mismatch (%u != %u)", id, expected_id);
     511                 :            : 
     512         [ +  + ]:         38 :                 if (type == SSH2_FXP_STATUS) {
     513                 :         15 :                         status = buffer_get_int(&msg);
     514                 :         15 :                         debug3("Received SSH2_FXP_STATUS %d", status);
     515         [ +  + ]:         15 :                         if (status == SSH2_FX_EOF)
     516                 :            :                                 break;
     517                 :          2 :                         error("Couldn't read directory: %s", fx2txt(status));
     518                 :          2 :                         goto out;
     519         [ -  + ]:         23 :                 } else if (type != SSH2_FXP_NAME)
     520                 :          0 :                         fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
     521                 :            :                             SSH2_FXP_NAME, type);
     522                 :            : 
     523                 :         23 :                 count = buffer_get_int(&msg);
     524         [ +  - ]:         23 :                 if (count == 0)
     525                 :            :                         break;
     526                 :         23 :                 debug3("Received %d SSH2_FXP_NAME responses", count);
     527         [ +  + ]:       1391 :                 for (i = 0; i < count; i++) {
     528                 :            :                         char *filename, *longname;
     529                 :            :                         Attrib *a;
     530                 :            : 
     531                 :       1353 :                         filename = buffer_get_string(&msg, NULL);
     532                 :       1353 :                         longname = buffer_get_string(&msg, NULL);
     533                 :       1353 :                         a = decode_attrib(&msg);
     534                 :            : 
     535         [ -  + ]:       1353 :                         if (print_flag)
     536                 :            :                                 printf("%s\n", longname);
     537                 :            : 
     538                 :            :                         /*
     539                 :            :                          * Directory entries should never contain '/'
     540                 :            :                          * These can be used to attack recursive ops
     541                 :            :                          * (e.g. send '../../../../etc/passwd')
     542                 :            :                          */
     543         [ -  + ]:       1353 :                         if (strchr(filename, '/') != NULL) {
     544                 :          0 :                                 error("Server sent suspect path \"%s\" "
     545                 :            :                                     "during readdir of \"%s\"", filename, path);
     546         [ +  - ]:       1353 :                         } else if (dir) {
     547                 :       1353 :                                 *dir = xrealloc(*dir, ents + 2, sizeof(**dir));
     548                 :       1353 :                                 (*dir)[ents] = xcalloc(1, sizeof(***dir));
     549                 :       1353 :                                 (*dir)[ents]->filename = xstrdup(filename);
     550                 :       1353 :                                 (*dir)[ents]->longname = xstrdup(longname);
     551                 :       1353 :                                 memcpy(&(*dir)[ents]->a, a, sizeof(*a));
     552                 :       1353 :                                 (*dir)[++ents] = NULL;
     553                 :            :                         }
     554                 :       1353 :                         free(filename);
     555                 :       1353 :                         free(longname);
     556                 :            :                 }
     557                 :            :         }
     558                 :            :         status = 0;
     559                 :            : 
     560                 :            :  out:
     561                 :         15 :         buffer_free(&msg);
     562                 :         15 :         do_close(conn, handle, handle_len);
     563                 :         15 :         free(handle);
     564                 :            : 
     565         [ +  + ]:         15 :         if (status != 0 && dir != NULL) {
     566                 :            :                 /* Don't return results on error */
     567                 :          2 :                 free_sftp_dirents(*dir);
     568                 :          2 :                 *dir = NULL;
     569 [ -  + ][ #  # ]:         13 :         } else if (interrupted && dir != NULL && *dir != NULL) {
                 [ #  # ]
     570                 :            :                 /* Don't return partial matches on interrupt */
     571                 :          0 :                 free_sftp_dirents(*dir);
     572                 :          0 :                 *dir = xcalloc(1, sizeof(**dir));
     573                 :          0 :                 **dir = NULL;
     574                 :            :         }
     575                 :            : 
     576                 :         15 :         return status;
     577                 :            : }
     578                 :            : 
     579                 :            : int
     580                 :         17 : do_readdir(struct sftp_conn *conn, char *path, SFTP_DIRENT ***dir)
     581                 :            : {
     582                 :         17 :         return(do_lsreaddir(conn, path, 0, dir));
     583                 :            : }
     584                 :            : 
     585                 :         15 : void free_sftp_dirents(SFTP_DIRENT **s)
     586                 :            : {
     587                 :            :         int i;
     588                 :            : 
     589         [ +  - ]:         15 :         if (s == NULL)
     590                 :         15 :                 return;
     591         [ +  + ]:       1368 :         for (i = 0; s[i]; i++) {
     592                 :       1353 :                 free(s[i]->filename);
     593                 :       1353 :                 free(s[i]->longname);
     594                 :       1353 :                 free(s[i]);
     595                 :            :         }
     596                 :         15 :         free(s);
     597                 :            : }
     598                 :            : 
     599                 :            : int
     600                 :          9 : do_rm(struct sftp_conn *conn, char *path)
     601                 :            : {
     602                 :            :         u_int status, id;
     603                 :            : 
     604                 :          9 :         debug2("Sending SSH2_FXP_REMOVE \"%s\"", path);
     605                 :            : 
     606                 :          9 :         id = conn->msg_id++;
     607                 :          9 :         send_string_request(conn, id, SSH2_FXP_REMOVE, path, strlen(path));
     608                 :          9 :         status = get_status(conn, id);
     609         [ +  + ]:          9 :         if (status != SSH2_FX_OK)
     610                 :          3 :                 error("Couldn't delete file: %s", fx2txt(status));
     611                 :          9 :         return(status);
     612                 :            : }
     613                 :            : 
     614                 :            : int
     615                 :          7 : do_mkdir(struct sftp_conn *conn, char *path, Attrib *a, int print_flag)
     616                 :            : {
     617                 :            :         u_int status, id;
     618                 :            : 
     619                 :          7 :         id = conn->msg_id++;
     620                 :          7 :         send_string_attrs_request(conn, id, SSH2_FXP_MKDIR, path,
     621                 :          7 :             strlen(path), a);
     622                 :            : 
     623                 :          7 :         status = get_status(conn, id);
     624         [ +  + ]:          7 :         if (status != SSH2_FX_OK && print_flag)
     625                 :          3 :                 error("Couldn't create directory: %s", fx2txt(status));
     626                 :            : 
     627                 :          7 :         return(status);
     628                 :            : }
     629                 :            : 
     630                 :            : int
     631                 :          7 : do_rmdir(struct sftp_conn *conn, char *path)
     632                 :            : {
     633                 :            :         u_int status, id;
     634                 :            : 
     635                 :          7 :         id = conn->msg_id++;
     636                 :          7 :         send_string_request(conn, id, SSH2_FXP_RMDIR, path,
     637                 :          7 :             strlen(path));
     638                 :            : 
     639                 :          7 :         status = get_status(conn, id);
     640         [ +  + ]:          7 :         if (status != SSH2_FX_OK)
     641                 :          3 :                 error("Couldn't remove directory: %s", fx2txt(status));
     642                 :            : 
     643                 :          7 :         return(status);
     644                 :            : }
     645                 :            : 
     646                 :            : Attrib *
     647                 :         97 : do_stat(struct sftp_conn *conn, char *path, int quiet)
     648                 :            : {
     649                 :            :         u_int id;
     650                 :            : 
     651                 :         97 :         id = conn->msg_id++;
     652                 :            : 
     653         [ +  - ]:         97 :         send_string_request(conn, id,
     654                 :         97 :             conn->version == 0 ? SSH2_FXP_STAT_VERSION_0 : SSH2_FXP_STAT,
     655                 :         97 :             path, strlen(path));
     656                 :            : 
     657                 :         97 :         return(get_decode_stat(conn, id, quiet));
     658                 :            : }
     659                 :            : 
     660                 :            : Attrib *
     661                 :        113 : do_lstat(struct sftp_conn *conn, char *path, int quiet)
     662                 :            : {
     663                 :            :         u_int id;
     664                 :            : 
     665         [ -  + ]:        113 :         if (conn->version == 0) {
     666         [ #  # ]:          0 :                 if (quiet)
     667                 :          0 :                         debug("Server version does not support lstat operation");
     668                 :            :                 else
     669                 :          0 :                         logit("Server version does not support lstat operation");
     670                 :          0 :                 return(do_stat(conn, path, quiet));
     671                 :            :         }
     672                 :            : 
     673                 :        113 :         id = conn->msg_id++;
     674                 :        113 :         send_string_request(conn, id, SSH2_FXP_LSTAT, path,
     675                 :        113 :             strlen(path));
     676                 :            : 
     677                 :        113 :         return(get_decode_stat(conn, id, quiet));
     678                 :            : }
     679                 :            : 
     680                 :            : #ifdef notyet
     681                 :            : Attrib *
     682                 :            : do_fstat(struct sftp_conn *conn, char *handle, u_int handle_len, int quiet)
     683                 :            : {
     684                 :            :         u_int id;
     685                 :            : 
     686                 :            :         id = conn->msg_id++;
     687                 :            :         send_string_request(conn, id, SSH2_FXP_FSTAT, handle,
     688                 :            :             handle_len);
     689                 :            : 
     690                 :            :         return(get_decode_stat(conn, id, quiet));
     691                 :            : }
     692                 :            : #endif
     693                 :            : 
     694                 :            : int
     695                 :          6 : do_setstat(struct sftp_conn *conn, char *path, Attrib *a)
     696                 :            : {
     697                 :            :         u_int status, id;
     698                 :            : 
     699                 :          6 :         id = conn->msg_id++;
     700                 :          6 :         send_string_attrs_request(conn, id, SSH2_FXP_SETSTAT, path,
     701                 :          6 :             strlen(path), a);
     702                 :            : 
     703                 :          6 :         status = get_status(conn, id);
     704         [ +  + ]:          6 :         if (status != SSH2_FX_OK)
     705                 :          3 :                 error("Couldn't setstat on \"%s\": %s", path,
     706                 :            :                     fx2txt(status));
     707                 :            : 
     708                 :          6 :         return(status);
     709                 :            : }
     710                 :            : 
     711                 :            : int
     712                 :          0 : do_fsetstat(struct sftp_conn *conn, char *handle, u_int handle_len,
     713                 :            :     Attrib *a)
     714                 :            : {
     715                 :            :         u_int status, id;
     716                 :            : 
     717                 :          0 :         id = conn->msg_id++;
     718                 :          0 :         send_string_attrs_request(conn, id, SSH2_FXP_FSETSTAT, handle,
     719                 :            :             handle_len, a);
     720                 :            : 
     721                 :          0 :         status = get_status(conn, id);
     722         [ #  # ]:          0 :         if (status != SSH2_FX_OK)
     723                 :          0 :                 error("Couldn't fsetstat: %s", fx2txt(status));
     724                 :            : 
     725                 :          0 :         return(status);
     726                 :            : }
     727                 :            : 
     728                 :            : char *
     729                 :        153 : do_realpath(struct sftp_conn *conn, char *path)
     730                 :            : {
     731                 :            :         Buffer msg;
     732                 :            :         u_int type, expected_id, count, id;
     733                 :            :         char *filename, *longname;
     734                 :            :         Attrib *a;
     735                 :            : 
     736                 :        153 :         expected_id = id = conn->msg_id++;
     737                 :        153 :         send_string_request(conn, id, SSH2_FXP_REALPATH, path,
     738                 :        153 :             strlen(path));
     739                 :            : 
     740                 :        153 :         buffer_init(&msg);
     741                 :            : 
     742                 :        153 :         get_msg(conn, &msg);
     743                 :        153 :         type = buffer_get_char(&msg);
     744                 :        153 :         id = buffer_get_int(&msg);
     745                 :            : 
     746         [ -  + ]:        153 :         if (id != expected_id)
     747                 :          0 :                 fatal("ID mismatch (%u != %u)", id, expected_id);
     748                 :            : 
     749         [ -  + ]:        153 :         if (type == SSH2_FXP_STATUS) {
     750                 :          0 :                 u_int status = buffer_get_int(&msg);
     751                 :            : 
     752                 :          0 :                 error("Couldn't canonicalize: %s", fx2txt(status));
     753                 :          0 :                 buffer_free(&msg);
     754                 :          0 :                 return NULL;
     755         [ -  + ]:        153 :         } else if (type != SSH2_FXP_NAME)
     756                 :          0 :                 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
     757                 :            :                     SSH2_FXP_NAME, type);
     758                 :            : 
     759                 :        153 :         count = buffer_get_int(&msg);
     760         [ -  + ]:        153 :         if (count != 1)
     761                 :          0 :                 fatal("Got multiple names (%d) from SSH_FXP_REALPATH", count);
     762                 :            : 
     763                 :        153 :         filename = buffer_get_string(&msg, NULL);
     764                 :        153 :         longname = buffer_get_string(&msg, NULL);
     765                 :        153 :         a = decode_attrib(&msg);
     766                 :            : 
     767                 :        153 :         debug3("SSH_FXP_REALPATH %s -> %s size %lu", path, filename,
     768                 :            :             (unsigned long)a->size);
     769                 :            : 
     770                 :        153 :         free(longname);
     771                 :            : 
     772                 :        153 :         buffer_free(&msg);
     773                 :            : 
     774                 :        153 :         return(filename);
     775                 :            : }
     776                 :            : 
     777                 :            : int
     778                 :         16 : do_rename(struct sftp_conn *conn, char *oldpath, char *newpath,
     779                 :            :     int force_legacy)
     780                 :            : {
     781                 :            :         Buffer msg;
     782                 :            :         u_int status, id;
     783 [ +  - ][ +  + ]:         16 :         int use_ext = (conn->exts & SFTP_EXT_POSIX_RENAME) && !force_legacy;
     784                 :            : 
     785                 :         16 :         buffer_init(&msg);
     786                 :            : 
     787                 :            :         /* Send rename request */
     788                 :         16 :         id = conn->msg_id++;
     789         [ +  + ]:         16 :         if (use_ext) {
     790                 :         10 :                 buffer_put_char(&msg, SSH2_FXP_EXTENDED);
     791                 :         10 :                 buffer_put_int(&msg, id);
     792                 :         10 :                 buffer_put_cstring(&msg, "posix-rename@openssh.com");
     793                 :            :         } else {
     794                 :          6 :                 buffer_put_char(&msg, SSH2_FXP_RENAME);
     795                 :          6 :                 buffer_put_int(&msg, id);
     796                 :            :         }
     797                 :         16 :         buffer_put_cstring(&msg, oldpath);
     798                 :         16 :         buffer_put_cstring(&msg, newpath);
     799                 :         16 :         send_msg(conn, &msg);
     800         [ +  + ]:         16 :         debug3("Sent message %s \"%s\" -> \"%s\"",
     801                 :            :             use_ext ? "posix-rename@openssh.com" : "SSH2_FXP_RENAME",
     802                 :            :             oldpath, newpath);
     803                 :         16 :         buffer_free(&msg);
     804                 :            : 
     805                 :         16 :         status = get_status(conn, id);
     806         [ +  + ]:         16 :         if (status != SSH2_FX_OK)
     807                 :          8 :                 error("Couldn't rename file \"%s\" to \"%s\": %s", oldpath,
     808                 :            :                     newpath, fx2txt(status));
     809                 :            : 
     810                 :         16 :         return(status);
     811                 :            : }
     812                 :            : 
     813                 :            : int
     814                 :          7 : do_hardlink(struct sftp_conn *conn, char *oldpath, char *newpath)
     815                 :            : {
     816                 :            :         Buffer msg;
     817                 :            :         u_int status, id;
     818                 :            : 
     819         [ -  + ]:          7 :         if ((conn->exts & SFTP_EXT_HARDLINK) == 0) {
     820                 :          0 :                 error("Server does not support hardlink@openssh.com extension");
     821                 :          0 :                 return -1;
     822                 :            :         }
     823                 :            : 
     824                 :          7 :         buffer_init(&msg);
     825                 :            : 
     826                 :            :         /* Send link request */
     827                 :          7 :         id = conn->msg_id++;
     828                 :          7 :         buffer_put_char(&msg, SSH2_FXP_EXTENDED);
     829                 :          7 :         buffer_put_int(&msg, id);
     830                 :          7 :         buffer_put_cstring(&msg, "hardlink@openssh.com");
     831                 :          7 :         buffer_put_cstring(&msg, oldpath);
     832                 :          7 :         buffer_put_cstring(&msg, newpath);
     833                 :          7 :         send_msg(conn, &msg);
     834                 :          7 :         debug3("Sent message hardlink@openssh.com \"%s\" -> \"%s\"",
     835                 :            :                oldpath, newpath);
     836                 :          7 :         buffer_free(&msg);
     837                 :            : 
     838                 :          7 :         status = get_status(conn, id);
     839         [ +  + ]:          7 :         if (status != SSH2_FX_OK)
     840                 :          3 :                 error("Couldn't link file \"%s\" to \"%s\": %s", oldpath,
     841                 :            :                     newpath, fx2txt(status));
     842                 :            : 
     843                 :          7 :         return(status);
     844                 :            : }
     845                 :            : 
     846                 :            : int
     847                 :          7 : do_symlink(struct sftp_conn *conn, char *oldpath, char *newpath)
     848                 :            : {
     849                 :            :         Buffer msg;
     850                 :            :         u_int status, id;
     851                 :            : 
     852         [ -  + ]:          7 :         if (conn->version < 3) {
     853                 :          0 :                 error("This server does not support the symlink operation");
     854                 :          0 :                 return(SSH2_FX_OP_UNSUPPORTED);
     855                 :            :         }
     856                 :            : 
     857                 :          7 :         buffer_init(&msg);
     858                 :            : 
     859                 :            :         /* Send symlink request */
     860                 :          7 :         id = conn->msg_id++;
     861                 :          7 :         buffer_put_char(&msg, SSH2_FXP_SYMLINK);
     862                 :          7 :         buffer_put_int(&msg, id);
     863                 :          7 :         buffer_put_cstring(&msg, oldpath);
     864                 :          7 :         buffer_put_cstring(&msg, newpath);
     865                 :          7 :         send_msg(conn, &msg);
     866                 :          7 :         debug3("Sent message SSH2_FXP_SYMLINK \"%s\" -> \"%s\"", oldpath,
     867                 :            :             newpath);
     868                 :          7 :         buffer_free(&msg);
     869                 :            : 
     870                 :          7 :         status = get_status(conn, id);
     871         [ +  + ]:          7 :         if (status != SSH2_FX_OK)
     872                 :          3 :                 error("Couldn't symlink file \"%s\" to \"%s\": %s", oldpath,
     873                 :            :                     newpath, fx2txt(status));
     874                 :            : 
     875                 :          7 :         return(status);
     876                 :            : }
     877                 :            : 
     878                 :            : int
     879                 :          0 : do_fsync(struct sftp_conn *conn, char *handle, u_int handle_len)
     880                 :            : {
     881                 :            :         Buffer msg;
     882                 :            :         u_int status, id;
     883                 :            : 
     884                 :            :         /* Silently return if the extension is not supported */
     885         [ #  # ]:          0 :         if ((conn->exts & SFTP_EXT_FSYNC) == 0)
     886                 :            :                 return -1;
     887                 :            : 
     888                 :          0 :         buffer_init(&msg);
     889                 :            : 
     890                 :            :         /* Send fsync request */
     891                 :          0 :         id = conn->msg_id++;
     892                 :            : 
     893                 :          0 :         buffer_put_char(&msg, SSH2_FXP_EXTENDED);
     894                 :          0 :         buffer_put_int(&msg, id);
     895                 :          0 :         buffer_put_cstring(&msg, "fsync@openssh.com");
     896                 :          0 :         buffer_put_string(&msg, handle, handle_len);
     897                 :          0 :         send_msg(conn, &msg);
     898                 :          0 :         debug3("Sent message fsync@openssh.com I:%u", id);
     899                 :          0 :         buffer_free(&msg);
     900                 :            : 
     901                 :          0 :         status = get_status(conn, id);
     902         [ #  # ]:          0 :         if (status != SSH2_FX_OK)
     903                 :          0 :                 error("Couldn't sync file: %s", fx2txt(status));
     904                 :            : 
     905                 :          0 :         return status;
     906                 :            : }
     907                 :            : 
     908                 :            : #ifdef notyet
     909                 :            : char *
     910                 :            : do_readlink(struct sftp_conn *conn, char *path)
     911                 :            : {
     912                 :            :         Buffer msg;
     913                 :            :         u_int type, expected_id, count, id;
     914                 :            :         char *filename, *longname;
     915                 :            :         Attrib *a;
     916                 :            : 
     917                 :            :         expected_id = id = conn->msg_id++;
     918                 :            :         send_string_request(conn, id, SSH2_FXP_READLINK, path, strlen(path));
     919                 :            : 
     920                 :            :         buffer_init(&msg);
     921                 :            : 
     922                 :            :         get_msg(conn, &msg);
     923                 :            :         type = buffer_get_char(&msg);
     924                 :            :         id = buffer_get_int(&msg);
     925                 :            : 
     926                 :            :         if (id != expected_id)
     927                 :            :                 fatal("ID mismatch (%u != %u)", id, expected_id);
     928                 :            : 
     929                 :            :         if (type == SSH2_FXP_STATUS) {
     930                 :            :                 u_int status = buffer_get_int(&msg);
     931                 :            : 
     932                 :            :                 error("Couldn't readlink: %s", fx2txt(status));
     933                 :            :                 buffer_free(&msg);
     934                 :            :                 return(NULL);
     935                 :            :         } else if (type != SSH2_FXP_NAME)
     936                 :            :                 fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
     937                 :            :                     SSH2_FXP_NAME, type);
     938                 :            : 
     939                 :            :         count = buffer_get_int(&msg);
     940                 :            :         if (count != 1)
     941                 :            :                 fatal("Got multiple names (%d) from SSH_FXP_READLINK", count);
     942                 :            : 
     943                 :            :         filename = buffer_get_string(&msg, NULL);
     944                 :            :         longname = buffer_get_string(&msg, NULL);
     945                 :            :         a = decode_attrib(&msg);
     946                 :            : 
     947                 :            :         debug3("SSH_FXP_READLINK %s -> %s", path, filename);
     948                 :            : 
     949                 :            :         free(longname);
     950                 :            : 
     951                 :            :         buffer_free(&msg);
     952                 :            : 
     953                 :            :         return(filename);
     954                 :            : }
     955                 :            : #endif
     956                 :            : 
     957                 :            : int
     958                 :          4 : do_statvfs(struct sftp_conn *conn, const char *path, struct sftp_statvfs *st,
     959                 :            :     int quiet)
     960                 :            : {
     961                 :            :         Buffer msg;
     962                 :            :         u_int id;
     963                 :            : 
     964         [ -  + ]:          4 :         if ((conn->exts & SFTP_EXT_STATVFS) == 0) {
     965                 :          0 :                 error("Server does not support statvfs@openssh.com extension");
     966                 :          0 :                 return -1;
     967                 :            :         }
     968                 :            : 
     969                 :          4 :         id = conn->msg_id++;
     970                 :            : 
     971                 :          4 :         buffer_init(&msg);
     972                 :          4 :         buffer_clear(&msg);
     973                 :          4 :         buffer_put_char(&msg, SSH2_FXP_EXTENDED);
     974                 :          4 :         buffer_put_int(&msg, id);
     975                 :          4 :         buffer_put_cstring(&msg, "statvfs@openssh.com");
     976                 :          4 :         buffer_put_cstring(&msg, path);
     977                 :          4 :         send_msg(conn, &msg);
     978                 :          4 :         buffer_free(&msg);
     979                 :            : 
     980                 :          4 :         return get_decode_statvfs(conn, st, id, quiet);
     981                 :            : }
     982                 :            : 
     983                 :            : #ifdef notyet
     984                 :            : int
     985                 :            : do_fstatvfs(struct sftp_conn *conn, const char *handle, u_int handle_len,
     986                 :            :     struct sftp_statvfs *st, int quiet)
     987                 :            : {
     988                 :            :         Buffer msg;
     989                 :            :         u_int id;
     990                 :            : 
     991                 :            :         if ((conn->exts & SFTP_EXT_FSTATVFS) == 0) {
     992                 :            :                 error("Server does not support fstatvfs@openssh.com extension");
     993                 :            :                 return -1;
     994                 :            :         }
     995                 :            : 
     996                 :            :         id = conn->msg_id++;
     997                 :            : 
     998                 :            :         buffer_init(&msg);
     999                 :            :         buffer_clear(&msg);
    1000                 :            :         buffer_put_char(&msg, SSH2_FXP_EXTENDED);
    1001                 :            :         buffer_put_int(&msg, id);
    1002                 :            :         buffer_put_cstring(&msg, "fstatvfs@openssh.com");
    1003                 :            :         buffer_put_string(&msg, handle, handle_len);
    1004                 :            :         send_msg(conn, &msg);
    1005                 :            :         buffer_free(&msg);
    1006                 :            : 
    1007                 :            :         return get_decode_statvfs(conn, st, id, quiet);
    1008                 :            : }
    1009                 :            : #endif
    1010                 :            : 
    1011                 :            : static void
    1012                 :     708152 : send_read_request(struct sftp_conn *conn, u_int id, u_int64_t offset,
    1013                 :            :     u_int len, char *handle, u_int handle_len)
    1014                 :            : {
    1015                 :            :         Buffer msg;
    1016                 :            : 
    1017                 :     708152 :         buffer_init(&msg);
    1018                 :     708152 :         buffer_clear(&msg);
    1019                 :     708152 :         buffer_put_char(&msg, SSH2_FXP_READ);
    1020                 :     708152 :         buffer_put_int(&msg, id);
    1021                 :     708152 :         buffer_put_string(&msg, handle, handle_len);
    1022                 :     708152 :         buffer_put_int64(&msg, offset);
    1023                 :     708152 :         buffer_put_int(&msg, len);
    1024                 :     708152 :         send_msg(conn, &msg);
    1025                 :     708152 :         buffer_free(&msg);
    1026                 :     708152 : }
    1027                 :            : 
    1028                 :            : int
    1029                 :         58 : do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
    1030                 :            :     Attrib *a, int preserve_flag, int resume_flag, int fsync_flag)
    1031                 :            : {
    1032                 :            :         Attrib junk;
    1033                 :            :         Buffer msg;
    1034                 :            :         char *handle;
    1035                 :         58 :         int local_fd = -1, status = 0, write_error;
    1036                 :         58 :         int read_error, write_errno, reordered = 0;
    1037                 :         58 :         u_int64_t offset = 0, size, highwater;
    1038                 :            :         u_int handle_len, mode, type, id, buflen, num_req, max_req;
    1039                 :            :         off_t progress_counter;
    1040                 :            :         struct stat st;
    1041                 :            :         struct request {
    1042                 :            :                 u_int id;
    1043                 :            :                 u_int len;
    1044                 :            :                 u_int64_t offset;
    1045                 :            :                 TAILQ_ENTRY(request) tq;
    1046                 :            :         };
    1047                 :            :         TAILQ_HEAD(reqhead, request) requests;
    1048                 :            :         struct request *req;
    1049                 :            : 
    1050                 :         58 :         TAILQ_INIT(&requests);
    1051                 :            : 
    1052 [ +  - ][ +  - ]:         58 :         if (a == NULL && (a = do_stat(conn, remote_path, 0)) == NULL)
    1053                 :            :                 return -1;
    1054                 :            : 
    1055                 :            :         /* Do not preserve set[ug]id here, as we do not preserve ownership */
    1056         [ +  - ]:         58 :         if (a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
    1057                 :         58 :                 mode = a->perm & 0777;
    1058                 :            :         else
    1059                 :            :                 mode = 0666;
    1060                 :            : 
    1061 [ +  - ][ -  + ]:         58 :         if ((a->flags & SSH2_FILEXFER_ATTR_PERMISSIONS) &&
    1062                 :         58 :             (!S_ISREG(a->perm))) {
    1063                 :          0 :                 error("Cannot download non-regular file: %s", remote_path);
    1064                 :          0 :                 return(-1);
    1065                 :            :         }
    1066                 :            : 
    1067         [ +  - ]:         58 :         if (a->flags & SSH2_FILEXFER_ATTR_SIZE)
    1068                 :         58 :                 size = a->size;
    1069                 :            :         else
    1070                 :            :                 size = 0;
    1071                 :            : 
    1072                 :         58 :         buflen = conn->transfer_buflen;
    1073                 :         58 :         buffer_init(&msg);
    1074                 :            : 
    1075                 :            :         /* Send open request */
    1076                 :         58 :         id = conn->msg_id++;
    1077                 :         58 :         buffer_put_char(&msg, SSH2_FXP_OPEN);
    1078                 :         58 :         buffer_put_int(&msg, id);
    1079                 :         58 :         buffer_put_cstring(&msg, remote_path);
    1080                 :         58 :         buffer_put_int(&msg, SSH2_FXF_READ);
    1081                 :         58 :         attrib_clear(&junk); /* Send empty attributes */
    1082                 :         58 :         encode_attrib(&msg, &junk);
    1083                 :         58 :         send_msg(conn, &msg);
    1084                 :         58 :         debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
    1085                 :            : 
    1086                 :         58 :         handle = get_handle(conn, id, &handle_len,
    1087                 :            :             "remote open(\"%s\")", remote_path);
    1088         [ +  + ]:         58 :         if (handle == NULL) {
    1089                 :          2 :                 buffer_free(&msg);
    1090                 :          2 :                 return(-1);
    1091                 :            :         }
    1092                 :            : 
    1093         [ +  - ]:         56 :         local_fd = open(local_path,
    1094                 :            :             O_WRONLY | O_CREAT | (resume_flag ? 0 : O_TRUNC), mode | S_IWUSR);
    1095         [ -  + ]:         56 :         if (local_fd == -1) {
    1096                 :          0 :                 error("Couldn't open local file \"%s\" for writing: %s",
    1097                 :          0 :                     local_path, strerror(errno));
    1098                 :          0 :                 goto fail;
    1099                 :            :         }
    1100                 :         56 :         offset = highwater = 0;
    1101         [ -  + ]:         56 :         if (resume_flag) {
    1102         [ #  # ]:          0 :                 if (fstat(local_fd, &st) == -1) {
    1103                 :          0 :                         error("Unable to stat local file \"%s\": %s",
    1104                 :          0 :                             local_path, strerror(errno));
    1105                 :          0 :                         goto fail;
    1106                 :            :                 }
    1107         [ #  # ]:          0 :                 if (st.st_size < 0) {
    1108                 :          0 :                         error("\"%s\" has negative size", local_path);
    1109                 :          0 :                         goto fail;
    1110                 :            :                 }
    1111         [ #  # ]:          0 :                 if ((u_int64_t)st.st_size > size) {
    1112                 :          0 :                         error("Unable to resume download of \"%s\": "
    1113                 :            :                             "local file is larger than remote", local_path);
    1114                 :            :  fail:
    1115                 :          0 :                         do_close(conn, handle, handle_len);
    1116                 :          0 :                         buffer_free(&msg);
    1117                 :          0 :                         free(handle);
    1118         [ #  # ]:          0 :                         if (local_fd != -1)
    1119                 :          0 :                                 close(local_fd);
    1120                 :            :                         return -1;
    1121                 :            :                 }
    1122                 :            :                 offset = highwater = st.st_size;
    1123                 :            :         }
    1124                 :            : 
    1125                 :            :         /* Read from remote and write to local */
    1126                 :         56 :         write_error = read_error = write_errno = num_req = 0;
    1127                 :         56 :         max_req = 1;
    1128                 :         56 :         progress_counter = offset;
    1129                 :            : 
    1130 [ -  + ][ #  # ]:         56 :         if (showprogress && size != 0)
    1131                 :         56 :                 start_progress_meter(remote_path, size, &progress_counter);
    1132                 :            : 
    1133         [ +  + ]:     708208 :         while (num_req > 0 || max_req > 0) {
    1134                 :            :                 char *data;
    1135                 :            :                 u_int len;
    1136                 :            : 
    1137                 :            :                 /*
    1138                 :            :                  * Simulate EOF on interrupt: stop sending new requests and
    1139                 :            :                  * allow outstanding requests to drain gracefully
    1140                 :            :                  */
    1141         [ -  + ]:     708152 :                 if (interrupted) {
    1142         [ #  # ]:     708152 :                         if (num_req == 0) /* If we haven't started yet... */
    1143                 :            :                                 break;
    1144                 :            :                         max_req = 0;
    1145                 :            :                 }
    1146                 :            : 
    1147                 :            :                 /* Send some more requests */
    1148         [ +  + ]:    1416250 :                 while (num_req < max_req) {
    1149                 :     708098 :                         debug3("Request range %llu -> %llu (%d/%d)",
    1150                 :            :                             (unsigned long long)offset,
    1151                 :     708098 :                             (unsigned long long)offset + buflen - 1,
    1152                 :            :                             num_req, max_req);
    1153                 :     708098 :                         req = xcalloc(1, sizeof(*req));
    1154                 :     708098 :                         req->id = conn->msg_id++;
    1155                 :     708098 :                         req->len = buflen;
    1156                 :     708098 :                         req->offset = offset;
    1157                 :     708098 :                         offset += buflen;
    1158                 :     708098 :                         num_req++;
    1159                 :     708098 :                         TAILQ_INSERT_TAIL(&requests, req, tq);
    1160                 :     708098 :                         send_read_request(conn, req->id, req->offset,
    1161                 :            :                             req->len, handle, handle_len);
    1162                 :            :                 }
    1163                 :            : 
    1164                 :     708152 :                 buffer_clear(&msg);
    1165                 :     708152 :                 get_msg(conn, &msg);
    1166                 :     708152 :                 type = buffer_get_char(&msg);
    1167                 :     708152 :                 id = buffer_get_int(&msg);
    1168                 :     708152 :                 debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
    1169                 :            : 
    1170                 :            :                 /* Find the request in our queue */
    1171         [ +  - ]:     708180 :                 for (req = TAILQ_FIRST(&requests);
    1172         [ +  + ]:     708180 :                     req != NULL && req->id != id;
    1173                 :         28 :                     req = TAILQ_NEXT(req, tq))
    1174                 :            :                         ;
    1175         [ -  + ]:     708152 :                 if (req == NULL)
    1176                 :          0 :                         fatal("Unexpected reply %u", id);
    1177                 :            : 
    1178      [ +  +  - ]:     708152 :                 switch (type) {
    1179                 :            :                 case SSH2_FXP_STATUS:
    1180                 :         84 :                         status = buffer_get_int(&msg);
    1181         [ +  + ]:         84 :                         if (status != SSH2_FX_EOF)
    1182                 :          2 :                                 read_error = 1;
    1183                 :         84 :                         max_req = 0;
    1184         [ -  + ]:         84 :                         TAILQ_REMOVE(&requests, req, tq);
    1185                 :         84 :                         free(req);
    1186                 :         84 :                         num_req--;
    1187                 :         84 :                         break;
    1188                 :            :                 case SSH2_FXP_DATA:
    1189                 :     708068 :                         data = buffer_get_string(&msg, &len);
    1190                 :     708068 :                         debug3("Received data %llu -> %llu",
    1191                 :            :                             (unsigned long long)req->offset,
    1192                 :     708068 :                             (unsigned long long)req->offset + len - 1);
    1193         [ -  + ]:     708068 :                         if (len > req->len)
    1194                 :          0 :                                 fatal("Received more data than asked for "
    1195                 :            :                                     "%u > %u", len, req->len);
    1196   [ +  -  -  + ]:    1416136 :                         if ((lseek(local_fd, req->offset, SEEK_SET) == -1 ||
    1197         [ #  # ]:     708068 :                             atomicio(vwrite, local_fd, data, len) != len) &&
    1198                 :            :                             !write_error) {
    1199                 :          0 :                                 write_errno = errno;
    1200                 :          0 :                                 write_error = 1;
    1201                 :          0 :                                 max_req = 0;
    1202                 :            :                         }
    1203 [ +  - ][ +  - ]:     708068 :                         else if (!reordered && req->offset <= highwater)
    1204                 :     708068 :                                 highwater = req->offset + len;
    1205 [ #  # ][ #  # ]:          0 :                         else if (!reordered && req->offset > highwater)
    1206                 :          0 :                                 reordered = 1;
    1207                 :     708068 :                         progress_counter += len;
    1208                 :     708068 :                         free(data);
    1209                 :            : 
    1210         [ +  + ]:     708068 :                         if (len == req->len) {
    1211         [ +  + ]:     708014 :                                 TAILQ_REMOVE(&requests, req, tq);
    1212                 :     708014 :                                 free(req);
    1213                 :     708014 :                                 num_req--;
    1214                 :            :                         } else {
    1215                 :            :                                 /* Resend the request for the missing data */
    1216                 :         54 :                                 debug3("Short data block, re-requesting "
    1217                 :            :                                     "%llu -> %llu (%2d)",
    1218                 :            :                                     (unsigned long long)req->offset + len,
    1219                 :         54 :                                     (unsigned long long)req->offset +
    1220                 :            :                                     req->len - 1, num_req);
    1221                 :         54 :                                 req->id = conn->msg_id++;
    1222                 :         54 :                                 req->len -= len;
    1223                 :         54 :                                 req->offset += len;
    1224                 :         54 :                                 send_read_request(conn, req->id,
    1225                 :            :                                     req->offset, req->len, handle, handle_len);
    1226                 :            :                                 /* Reduce the request size */
    1227         [ +  - ]:         54 :                                 if (len < buflen)
    1228                 :         54 :                                         buflen = MAX(MIN_READ_SIZE, len);
    1229                 :            :                         }
    1230         [ +  - ]:     708068 :                         if (max_req > 0) { /* max_req = 0 iff EOF received */
    1231         [ +  + ]:     708068 :                                 if (size > 0 && offset > size) {
    1232                 :            :                                         /* Only one request at a time
    1233                 :            :                                          * after the expected EOF */
    1234                 :        389 :                                         debug3("Finish at %llu (%2d)",
    1235                 :            :                                             (unsigned long long)offset,
    1236                 :            :                                             num_req);
    1237                 :        389 :                                         max_req = 1;
    1238         [ +  + ]:     707679 :                                 } else if (max_req <= conn->num_requests) {
    1239                 :        363 :                                         ++max_req;
    1240                 :            :                                 }
    1241                 :            :                         }
    1242                 :            :                         break;
    1243                 :            :                 default:
    1244                 :     708152 :                         fatal("Expected SSH2_FXP_DATA(%u) packet, got %u",
    1245                 :            :                             SSH2_FXP_DATA, type);
    1246                 :            :                 }
    1247                 :            :         }
    1248                 :            : 
    1249 [ -  + ][ #  # ]:         56 :         if (showprogress && size)
    1250                 :          0 :                 stop_progress_meter();
    1251                 :            : 
    1252                 :            :         /* Sanity check */
    1253         [ -  + ]:         56 :         if (TAILQ_FIRST(&requests) != NULL)
    1254                 :          0 :                 fatal("Transfer complete, but requests still in queue");
    1255                 :            :         /* Truncate at highest contiguous point to avoid holes on interrupt */
    1256 [ +  + ][ -  + ]:         56 :         if (read_error || write_error || interrupted) {
    1257         [ -  + ]:          2 :                 if (reordered && resume_flag) {
    1258                 :          0 :                         error("Unable to resume download of \"%s\": "
    1259                 :            :                             "server reordered requests", local_path);
    1260                 :            :                 }
    1261                 :          2 :                 debug("truncating at %llu", (unsigned long long)highwater);
    1262                 :          2 :                 ftruncate(local_fd, highwater);
    1263                 :            :         }
    1264         [ +  + ]:         56 :         if (read_error) {
    1265                 :          2 :                 error("Couldn't read from remote file \"%s\" : %s",
    1266                 :            :                     remote_path, fx2txt(status));
    1267                 :          2 :                 status = -1;
    1268                 :          2 :                 do_close(conn, handle, handle_len);
    1269         [ -  + ]:         54 :         } else if (write_error) {
    1270                 :          0 :                 error("Couldn't write to \"%s\": %s", local_path,
    1271                 :            :                     strerror(write_errno));
    1272                 :          0 :                 status = -1;
    1273                 :          0 :                 do_close(conn, handle, handle_len);
    1274                 :            :         } else {
    1275                 :         54 :                 status = do_close(conn, handle, handle_len);
    1276 [ +  - ][ -  + ]:         54 :                 if (interrupted || status != SSH2_FX_OK)
    1277                 :          0 :                         status = -1;
    1278                 :            :                 /* Override umask and utimes if asked */
    1279                 :            : #ifdef HAVE_FCHMOD
    1280 [ -  + ][ #  # ]:         54 :                 if (preserve_flag && fchmod(local_fd, mode) == -1)
    1281                 :            : #else
    1282                 :            :                 if (preserve_flag && chmod(local_path, mode) == -1)
    1283                 :            : #endif /* HAVE_FCHMOD */
    1284                 :          0 :                         error("Couldn't set mode on \"%s\": %s", local_path,
    1285                 :          0 :                             strerror(errno));
    1286 [ -  + ][ #  # ]:         54 :                 if (preserve_flag &&
    1287                 :          0 :                     (a->flags & SSH2_FILEXFER_ATTR_ACMODTIME)) {
    1288                 :            :                         struct timeval tv[2];
    1289                 :          0 :                         tv[0].tv_sec = a->atime;
    1290                 :          0 :                         tv[1].tv_sec = a->mtime;
    1291                 :          0 :                         tv[0].tv_usec = tv[1].tv_usec = 0;
    1292         [ #  # ]:          0 :                         if (utimes(local_path, tv) == -1)
    1293                 :          0 :                                 error("Can't set times on \"%s\": %s",
    1294                 :          0 :                                     local_path, strerror(errno));
    1295                 :            :                 }
    1296         [ -  + ]:         54 :                 if (fsync_flag) {
    1297                 :          0 :                         debug("syncing \"%s\"", local_path);
    1298         [ #  # ]:          0 :                         if (fsync(local_fd) == -1)
    1299                 :          0 :                                 error("Couldn't sync file \"%s\": %s",
    1300                 :          0 :                                     local_path, strerror(errno));
    1301                 :            :                 }
    1302                 :            :         }
    1303                 :         56 :         close(local_fd);
    1304                 :         56 :         buffer_free(&msg);
    1305                 :         56 :         free(handle);
    1306                 :            : 
    1307                 :         56 :         return(status);
    1308                 :            : }
    1309                 :            : 
    1310                 :            : static int
    1311                 :          0 : download_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
    1312                 :            :     Attrib *dirattrib, int preserve_flag, int print_flag, int resume_flag,
    1313                 :            :     int fsync_flag)
    1314                 :            : {
    1315                 :          0 :         int i, ret = 0;
    1316                 :            :         SFTP_DIRENT **dir_entries;
    1317                 :            :         char *filename, *new_src, *new_dst;
    1318                 :          0 :         mode_t mode = 0777;
    1319                 :            : 
    1320         [ #  # ]:          0 :         if (depth >= MAX_DIR_DEPTH) {
    1321                 :          0 :                 error("Maximum directory depth exceeded: %d levels", depth);
    1322                 :          0 :                 return -1;
    1323                 :            :         }
    1324                 :            : 
    1325 [ #  # ][ #  # ]:          0 :         if (dirattrib == NULL &&
    1326                 :            :             (dirattrib = do_stat(conn, src, 1)) == NULL) {
    1327                 :          0 :                 error("Unable to stat remote directory \"%s\"", src);
    1328                 :          0 :                 return -1;
    1329                 :            :         }
    1330         [ #  # ]:          0 :         if (!S_ISDIR(dirattrib->perm)) {
    1331                 :          0 :                 error("\"%s\" is not a directory", src);
    1332                 :          0 :                 return -1;
    1333                 :            :         }
    1334         [ #  # ]:          0 :         if (print_flag)
    1335                 :            :                 printf("Retrieving %s\n", src);
    1336                 :            : 
    1337         [ #  # ]:          0 :         if (dirattrib->flags & SSH2_FILEXFER_ATTR_PERMISSIONS)
    1338                 :          0 :                 mode = dirattrib->perm & 01777;
    1339                 :            :         else {
    1340                 :          0 :                 debug("Server did not send permissions for "
    1341                 :            :                     "directory \"%s\"", dst);
    1342                 :            :         }
    1343                 :            : 
    1344 [ #  # ][ #  # ]:          0 :         if (mkdir(dst, mode) == -1 && errno != EEXIST) {
    1345                 :          0 :                 error("mkdir %s: %s", dst, strerror(errno));
    1346                 :          0 :                 return -1;
    1347                 :            :         }
    1348                 :            : 
    1349         [ #  # ]:          0 :         if (do_readdir(conn, src, &dir_entries) == -1) {
    1350                 :          0 :                 error("%s: Failed to get directory contents", src);
    1351                 :          0 :                 return -1;
    1352                 :            :         }
    1353                 :            : 
    1354 [ #  # ][ #  # ]:          0 :         for (i = 0; dir_entries[i] != NULL && !interrupted; i++) {
    1355                 :          0 :                 filename = dir_entries[i]->filename;
    1356                 :            : 
    1357                 :          0 :                 new_dst = path_append(dst, filename);
    1358                 :          0 :                 new_src = path_append(src, filename);
    1359                 :            : 
    1360         [ #  # ]:          0 :                 if (S_ISDIR(dir_entries[i]->a.perm)) {
    1361 [ #  # ][ #  # ]:          0 :                         if (strcmp(filename, ".") == 0 ||
                 [ #  # ]
    1362 [ #  # ][ #  # ]:          0 :                             strcmp(filename, "..") == 0)
    1363                 :          0 :                                 continue;
    1364         [ #  # ]:          0 :                         if (download_dir_internal(conn, new_src, new_dst,
    1365                 :            :                             depth + 1, &(dir_entries[i]->a), preserve_flag,
    1366                 :            :                             print_flag, resume_flag, fsync_flag) == -1)
    1367                 :          0 :                                 ret = -1;
    1368         [ #  # ]:          0 :                 } else if (S_ISREG(dir_entries[i]->a.perm) ) {
    1369         [ #  # ]:          0 :                         if (do_download(conn, new_src, new_dst,
    1370                 :            :                             &(dir_entries[i]->a), preserve_flag,
    1371                 :            :                             resume_flag, fsync_flag) == -1) {
    1372                 :          0 :                                 error("Download of file %s to %s failed",
    1373                 :            :                                     new_src, new_dst);
    1374                 :          0 :                                 ret = -1;
    1375                 :            :                         }
    1376                 :            :                 } else
    1377                 :          0 :                         logit("%s: not a regular file\n", new_src);
    1378                 :            : 
    1379                 :          0 :                 free(new_dst);
    1380                 :          0 :                 free(new_src);
    1381                 :            :         }
    1382                 :            : 
    1383         [ #  # ]:          0 :         if (preserve_flag) {
    1384         [ #  # ]:          0 :                 if (dirattrib->flags & SSH2_FILEXFER_ATTR_ACMODTIME) {
    1385                 :            :                         struct timeval tv[2];
    1386                 :          0 :                         tv[0].tv_sec = dirattrib->atime;
    1387                 :          0 :                         tv[1].tv_sec = dirattrib->mtime;
    1388                 :          0 :                         tv[0].tv_usec = tv[1].tv_usec = 0;
    1389         [ #  # ]:          0 :                         if (utimes(dst, tv) == -1)
    1390                 :          0 :                                 error("Can't set times on \"%s\": %s",
    1391                 :          0 :                                     dst, strerror(errno));
    1392                 :            :                 } else
    1393                 :          0 :                         debug("Server did not send times for directory "
    1394                 :            :                             "\"%s\"", dst);
    1395                 :            :         }
    1396                 :            : 
    1397                 :          0 :         free_sftp_dirents(dir_entries);
    1398                 :            : 
    1399                 :          0 :         return ret;
    1400                 :            : }
    1401                 :            : 
    1402                 :            : int
    1403                 :          0 : download_dir(struct sftp_conn *conn, char *src, char *dst,
    1404                 :            :     Attrib *dirattrib, int preserve_flag, int print_flag,
    1405                 :            :     int resume_flag, int fsync_flag)
    1406                 :            : {
    1407                 :            :         char *src_canon;
    1408                 :            :         int ret;
    1409                 :            : 
    1410         [ #  # ]:          0 :         if ((src_canon = do_realpath(conn, src)) == NULL) {
    1411                 :          0 :                 error("Unable to canonicalize path \"%s\"", src);
    1412                 :          0 :                 return -1;
    1413                 :            :         }
    1414                 :            : 
    1415                 :          0 :         ret = download_dir_internal(conn, src_canon, dst, 0,
    1416                 :            :             dirattrib, preserve_flag, print_flag, resume_flag, fsync_flag);
    1417                 :          0 :         free(src_canon);
    1418                 :          0 :         return ret;
    1419                 :            : }
    1420                 :            : 
    1421                 :            : int
    1422                 :         29 : do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
    1423                 :            :     int preserve_flag, int fsync_flag)
    1424                 :            : {
    1425                 :            :         int local_fd;
    1426                 :         29 :         int status = SSH2_FX_OK;
    1427                 :            :         u_int handle_len, id, type;
    1428                 :            :         off_t offset, progress_counter;
    1429                 :            :         char *handle, *data;
    1430                 :            :         Buffer msg;
    1431                 :            :         struct stat sb;
    1432                 :            :         Attrib a;
    1433                 :            :         u_int32_t startid;
    1434                 :            :         u_int32_t ackid;
    1435                 :            :         struct outstanding_ack {
    1436                 :            :                 u_int id;
    1437                 :            :                 u_int len;
    1438                 :            :                 off_t offset;
    1439                 :            :                 TAILQ_ENTRY(outstanding_ack) tq;
    1440                 :            :         };
    1441                 :            :         TAILQ_HEAD(ackhead, outstanding_ack) acks;
    1442                 :         29 :         struct outstanding_ack *ack = NULL;
    1443                 :            : 
    1444                 :         29 :         TAILQ_INIT(&acks);
    1445                 :            : 
    1446         [ -  + ]:         29 :         if ((local_fd = open(local_path, O_RDONLY, 0)) == -1) {
    1447                 :          0 :                 error("Couldn't open local file \"%s\" for reading: %s",
    1448                 :          0 :                     local_path, strerror(errno));
    1449                 :          0 :                 return(-1);
    1450                 :            :         }
    1451         [ -  + ]:         29 :         if (fstat(local_fd, &sb) == -1) {
    1452                 :          0 :                 error("Couldn't fstat local file \"%s\": %s",
    1453                 :          0 :                     local_path, strerror(errno));
    1454                 :          0 :                 close(local_fd);
    1455                 :          0 :                 return(-1);
    1456                 :            :         }
    1457         [ -  + ]:         29 :         if (!S_ISREG(sb.st_mode)) {
    1458                 :          0 :                 error("%s is not a regular file", local_path);
    1459                 :          0 :                 close(local_fd);
    1460                 :          0 :                 return(-1);
    1461                 :            :         }
    1462                 :         29 :         stat_to_attrib(&sb, &a);
    1463                 :            : 
    1464                 :         29 :         a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
    1465                 :         29 :         a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
    1466                 :         29 :         a.perm &= 0777;
    1467         [ +  - ]:         29 :         if (!preserve_flag)
    1468                 :         29 :                 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
    1469                 :            : 
    1470                 :         29 :         buffer_init(&msg);
    1471                 :            : 
    1472                 :            :         /* Send open request */
    1473                 :         29 :         id = conn->msg_id++;
    1474                 :         29 :         buffer_put_char(&msg, SSH2_FXP_OPEN);
    1475                 :         29 :         buffer_put_int(&msg, id);
    1476                 :         29 :         buffer_put_cstring(&msg, remote_path);
    1477                 :         29 :         buffer_put_int(&msg, SSH2_FXF_WRITE|SSH2_FXF_CREAT|SSH2_FXF_TRUNC);
    1478                 :         29 :         encode_attrib(&msg, &a);
    1479                 :         29 :         send_msg(conn, &msg);
    1480                 :         29 :         debug3("Sent message SSH2_FXP_OPEN I:%u P:%s", id, remote_path);
    1481                 :            : 
    1482                 :         29 :         buffer_clear(&msg);
    1483                 :            : 
    1484                 :         29 :         handle = get_handle(conn, id, &handle_len,
    1485                 :            :             "remote open(\"%s\")", remote_path);
    1486         [ +  + ]:         29 :         if (handle == NULL) {
    1487                 :          1 :                 close(local_fd);
    1488                 :          1 :                 buffer_free(&msg);
    1489                 :          1 :                 return -1;
    1490                 :            :         }
    1491                 :            : 
    1492                 :         28 :         startid = ackid = id + 1;
    1493                 :         28 :         data = xmalloc(conn->transfer_buflen);
    1494                 :            : 
    1495                 :            :         /* Read from local and write to remote */
    1496                 :         28 :         offset = progress_counter = 0;
    1497         [ -  + ]:         28 :         if (showprogress)
    1498                 :         28 :                 start_progress_meter(local_path, sb.st_size,
    1499                 :            :                     &progress_counter);
    1500                 :            : 
    1501                 :            :         for (;;) {
    1502                 :            :                 int len;
    1503                 :            : 
    1504                 :            :                 /*
    1505                 :            :                  * Can't use atomicio here because it returns 0 on EOF,
    1506                 :            :                  * thus losing the last block of the file.
    1507                 :            :                  * Simulate an EOF on interrupt, allowing ACKs from the
    1508                 :            :                  * server to drain.
    1509                 :            :                  */
    1510 [ +  - ][ +  + ]:     708242 :                 if (interrupted || status != SSH2_FX_OK)
    1511                 :            :                         len = 0;
    1512                 :            :                 else do
    1513                 :    1416480 :                         len = read(local_fd, data, conn->transfer_buflen);
    1514         [ #  # ]:          0 :                 while ((len == -1) &&
    1515 [ -  + ][ #  # ]:     708240 :                     (errno == EINTR || errno == EAGAIN || errno == EWOULDBLOCK));
    1516                 :            : 
    1517         [ -  + ]:     708242 :                 if (len == -1)
    1518                 :          0 :                         fatal("Couldn't read from \"%s\": %s", local_path,
    1519                 :          0 :                             strerror(errno));
    1520                 :            : 
    1521         [ +  + ]:     708242 :                 if (len != 0) {
    1522                 :     707804 :                         ack = xcalloc(1, sizeof(*ack));
    1523                 :     707804 :                         ack->id = ++id;
    1524                 :     707804 :                         ack->offset = offset;
    1525                 :     707804 :                         ack->len = len;
    1526                 :     707804 :                         TAILQ_INSERT_TAIL(&acks, ack, tq);
    1527                 :            : 
    1528                 :     707804 :                         buffer_clear(&msg);
    1529                 :     707804 :                         buffer_put_char(&msg, SSH2_FXP_WRITE);
    1530                 :     707804 :                         buffer_put_int(&msg, ack->id);
    1531                 :     707804 :                         buffer_put_string(&msg, handle, handle_len);
    1532                 :     707804 :                         buffer_put_int64(&msg, offset);
    1533                 :     707804 :                         buffer_put_string(&msg, data, len);
    1534                 :     707804 :                         send_msg(conn, &msg);
    1535                 :     707804 :                         debug3("Sent message SSH2_FXP_WRITE I:%u O:%llu S:%u",
    1536                 :            :                             id, (unsigned long long)offset, len);
    1537         [ +  + ]:        438 :                 } else if (TAILQ_FIRST(&acks) == NULL)
    1538                 :            :                         break;
    1539                 :            : 
    1540         [ -  + ]:     708214 :                 if (ack == NULL)
    1541                 :          0 :                         fatal("Unexpected ACK %u", id);
    1542                 :            : 
    1543 [ +  + ][ +  + ]:     708214 :                 if (id == startid || len == 0 ||
    1544                 :     707776 :                     id - ackid >= conn->num_requests) {
    1545                 :            :                         u_int r_id;
    1546                 :            : 
    1547                 :     707804 :                         buffer_clear(&msg);
    1548                 :     707804 :                         get_msg(conn, &msg);
    1549                 :     707804 :                         type = buffer_get_char(&msg);
    1550                 :     707804 :                         r_id = buffer_get_int(&msg);
    1551                 :            : 
    1552         [ -  + ]:     707804 :                         if (type != SSH2_FXP_STATUS)
    1553                 :          0 :                                 fatal("Expected SSH2_FXP_STATUS(%d) packet, "
    1554                 :            :                                     "got %d", SSH2_FXP_STATUS, type);
    1555                 :            : 
    1556                 :     707804 :                         status = buffer_get_int(&msg);
    1557                 :     707804 :                         debug3("SSH2_FXP_STATUS %d", status);
    1558                 :            : 
    1559                 :            :                         /* Find the request in our queue */
    1560         [ +  - ]:     707804 :                         for (ack = TAILQ_FIRST(&acks);
    1561         [ -  + ]:     707804 :                             ack != NULL && ack->id != r_id;
    1562                 :          0 :                             ack = TAILQ_NEXT(ack, tq))
    1563                 :            :                                 ;
    1564         [ -  + ]:     707804 :                         if (ack == NULL)
    1565                 :          0 :                                 fatal("Can't find request for ID %u", r_id);
    1566         [ +  + ]:     707804 :                         TAILQ_REMOVE(&acks, ack, tq);
    1567                 :     707804 :                         debug3("In write loop, ack for %u %u bytes at %lld",
    1568                 :     707804 :                             ack->id, ack->len, (long long)ack->offset);
    1569                 :     707804 :                         ++ackid;
    1570                 :     707804 :                         progress_counter += ack->len;
    1571                 :     707804 :                         free(ack);
    1572                 :            :                 }
    1573                 :     708214 :                 offset += len;
    1574         [ +  - ]:     708214 :                 if (offset < 0)
    1575                 :          0 :                         fatal("%s: offset < 0", __func__);
    1576                 :            :         }
    1577                 :         28 :         buffer_free(&msg);
    1578                 :            : 
    1579         [ -  + ]:         28 :         if (showprogress)
    1580                 :          0 :                 stop_progress_meter();
    1581                 :         28 :         free(data);
    1582                 :            : 
    1583         [ +  + ]:         28 :         if (status != SSH2_FX_OK) {
    1584                 :          2 :                 error("Couldn't write to remote file \"%s\": %s",
    1585                 :            :                     remote_path, fx2txt(status));
    1586                 :          2 :                 status = -1;
    1587                 :            :         }
    1588                 :            : 
    1589         [ -  + ]:         28 :         if (close(local_fd) == -1) {
    1590                 :          0 :                 error("Couldn't close local file \"%s\": %s", local_path,
    1591                 :          0 :                     strerror(errno));
    1592                 :          0 :                 status = -1;
    1593                 :            :         }
    1594                 :            : 
    1595                 :            :         /* Override umask and utimes if asked */
    1596         [ -  + ]:         28 :         if (preserve_flag)
    1597                 :          0 :                 do_fsetstat(conn, handle, handle_len, &a);
    1598                 :            : 
    1599         [ -  + ]:         28 :         if (fsync_flag)
    1600                 :          0 :                 (void)do_fsync(conn, handle, handle_len);
    1601                 :            : 
    1602         [ -  + ]:         28 :         if (do_close(conn, handle, handle_len) != SSH2_FX_OK)
    1603                 :          0 :                 status = -1;
    1604                 :         28 :         free(handle);
    1605                 :            : 
    1606                 :         28 :         return status;
    1607                 :            : }
    1608                 :            : 
    1609                 :            : static int
    1610                 :          0 : upload_dir_internal(struct sftp_conn *conn, char *src, char *dst, int depth,
    1611                 :            :     int preserve_flag, int print_flag, int fsync_flag)
    1612                 :            : {
    1613                 :          0 :         int ret = 0, status;
    1614                 :            :         DIR *dirp;
    1615                 :            :         struct dirent *dp;
    1616                 :            :         char *filename, *new_src, *new_dst;
    1617                 :            :         struct stat sb;
    1618                 :            :         Attrib a;
    1619                 :            : 
    1620         [ #  # ]:          0 :         if (depth >= MAX_DIR_DEPTH) {
    1621                 :          0 :                 error("Maximum directory depth exceeded: %d levels", depth);
    1622                 :          0 :                 return -1;
    1623                 :            :         }
    1624                 :            : 
    1625         [ #  # ]:          0 :         if (stat(src, &sb) == -1) {
    1626                 :          0 :                 error("Couldn't stat directory \"%s\": %s",
    1627                 :          0 :                     src, strerror(errno));
    1628                 :          0 :                 return -1;
    1629                 :            :         }
    1630         [ #  # ]:          0 :         if (!S_ISDIR(sb.st_mode)) {
    1631                 :          0 :                 error("\"%s\" is not a directory", src);
    1632                 :          0 :                 return -1;
    1633                 :            :         }
    1634         [ #  # ]:          0 :         if (print_flag)
    1635                 :            :                 printf("Entering %s\n", src);
    1636                 :            : 
    1637                 :          0 :         attrib_clear(&a);
    1638                 :          0 :         stat_to_attrib(&sb, &a);
    1639                 :          0 :         a.flags &= ~SSH2_FILEXFER_ATTR_SIZE;
    1640                 :          0 :         a.flags &= ~SSH2_FILEXFER_ATTR_UIDGID;
    1641                 :          0 :         a.perm &= 01777;
    1642         [ #  # ]:          0 :         if (!preserve_flag)
    1643                 :          0 :                 a.flags &= ~SSH2_FILEXFER_ATTR_ACMODTIME;
    1644                 :            : 
    1645                 :          0 :         status = do_mkdir(conn, dst, &a, 0);
    1646                 :            :         /*
    1647                 :            :          * we lack a portable status for errno EEXIST,
    1648                 :            :          * so if we get a SSH2_FX_FAILURE back we must check
    1649                 :            :          * if it was created successfully.
    1650                 :            :          */
    1651         [ #  # ]:          0 :         if (status != SSH2_FX_OK) {
    1652         [ #  # ]:          0 :                 if (status != SSH2_FX_FAILURE)
    1653                 :            :                         return -1;
    1654         [ #  # ]:          0 :                 if (do_stat(conn, dst, 0) == NULL)
    1655                 :            :                         return -1;
    1656                 :            :         }
    1657                 :            : 
    1658         [ #  # ]:          0 :         if ((dirp = opendir(src)) == NULL) {
    1659                 :          0 :                 error("Failed to open dir \"%s\": %s", src, strerror(errno));
    1660                 :          0 :                 return -1;
    1661                 :            :         }
    1662                 :            : 
    1663 [ #  # ][ #  # ]:          0 :         while (((dp = readdir(dirp)) != NULL) && !interrupted) {
    1664         [ #  # ]:          0 :                 if (dp->d_ino == 0)
    1665                 :          0 :                         continue;
    1666                 :          0 :                 filename = dp->d_name;
    1667                 :          0 :                 new_dst = path_append(dst, filename);
    1668                 :          0 :                 new_src = path_append(src, filename);
    1669                 :            : 
    1670         [ #  # ]:          0 :                 if (lstat(new_src, &sb) == -1) {
    1671                 :          0 :                         logit("%s: lstat failed: %s", filename,
    1672                 :          0 :                             strerror(errno));
    1673                 :          0 :                         ret = -1;
    1674         [ #  # ]:          0 :                 } else if (S_ISDIR(sb.st_mode)) {
    1675 [ #  # ][ #  # ]:          0 :                         if (strcmp(filename, ".") == 0 ||
                 [ #  # ]
    1676 [ #  # ][ #  # ]:          0 :                             strcmp(filename, "..") == 0)
    1677                 :          0 :                                 continue;
    1678                 :            : 
    1679         [ #  # ]:          0 :                         if (upload_dir_internal(conn, new_src, new_dst,
    1680                 :            :                             depth + 1, preserve_flag, print_flag,
    1681                 :            :                             fsync_flag) == -1)
    1682                 :          0 :                                 ret = -1;
    1683         [ #  # ]:          0 :                 } else if (S_ISREG(sb.st_mode)) {
    1684         [ #  # ]:          0 :                         if (do_upload(conn, new_src, new_dst,
    1685                 :            :                             preserve_flag, fsync_flag) == -1) {
    1686                 :          0 :                                 error("Uploading of file %s to %s failed!",
    1687                 :            :                                     new_src, new_dst);
    1688                 :          0 :                                 ret = -1;
    1689                 :            :                         }
    1690                 :            :                 } else
    1691                 :          0 :                         logit("%s: not a regular file\n", filename);
    1692                 :          0 :                 free(new_dst);
    1693                 :          0 :                 free(new_src);
    1694                 :            :         }
    1695                 :            : 
    1696                 :          0 :         do_setstat(conn, dst, &a);
    1697                 :            : 
    1698                 :          0 :         (void) closedir(dirp);
    1699                 :          0 :         return ret;
    1700                 :            : }
    1701                 :            : 
    1702                 :            : int
    1703                 :          0 : upload_dir(struct sftp_conn *conn, char *src, char *dst, int preserve_flag,
    1704                 :            :     int print_flag, int fsync_flag)
    1705                 :            : {
    1706                 :            :         char *dst_canon;
    1707                 :            :         int ret;
    1708                 :            : 
    1709         [ #  # ]:          0 :         if ((dst_canon = do_realpath(conn, dst)) == NULL) {
    1710                 :          0 :                 error("Unable to canonicalize path \"%s\"", dst);
    1711                 :          0 :                 return -1;
    1712                 :            :         }
    1713                 :            : 
    1714                 :          0 :         ret = upload_dir_internal(conn, src, dst_canon, 0, preserve_flag,
    1715                 :            :             print_flag, fsync_flag);
    1716                 :            : 
    1717                 :          0 :         free(dst_canon);
    1718                 :          0 :         return ret;
    1719                 :            : }
    1720                 :            : 
    1721                 :            : char *
    1722                 :        754 : path_append(char *p1, char *p2)
    1723                 :            : {
    1724                 :            :         char *ret;
    1725                 :        754 :         size_t len = strlen(p1) + strlen(p2) + 2;
    1726                 :            : 
    1727                 :        754 :         ret = xmalloc(len);
    1728                 :        754 :         strlcpy(ret, p1, len);
    1729 [ +  - ][ +  + ]:        754 :         if (p1[0] != '\0' && p1[strlen(p1) - 1] != '/')
    1730                 :        143 :                 strlcat(ret, "/", len);
    1731                 :        754 :         strlcat(ret, p2, len);
    1732                 :            : 
    1733                 :        754 :         return(ret);
    1734                 :            : }
    1735                 :            : 

Generated by: LCOV version 1.9