]> andersk Git - openssh.git/blobdiff - sftp-client.c
- avsm@cvs.openbsd.org 2005/05/24 17:32:44
[openssh.git] / sftp-client.c
index bf2eb43accd9667ef816e30b49f9b1b85e175a8f..47297898a52d3101966562a8b1079d803f907035 100644 (file)
@@ -20,7 +20,7 @@
 /* XXX: copy between two remote sites */
 
 #include "includes.h"
-RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $");
+RCSID("$OpenBSD: sftp-client.c,v 1.54 2005/05/24 17:32:44 avsm Exp $");
 
 #include "openbsd-compat/sys-queue.h"
 
@@ -36,6 +36,7 @@ RCSID("$OpenBSD: sftp-client.c,v 1.48 2004/03/30 12:41:56 djm Exp $");
 #include "sftp-common.h"
 #include "sftp-client.h"
 
+extern volatile sig_atomic_t interrupted;
 extern int showprogress;
 
 /* Minimum amount of data to read at at time */
@@ -63,10 +64,10 @@ send_msg(int fd, Buffer *m)
 
        /* Send length first */
        PUT_32BIT(mlen, buffer_len(m));
-       if (atomicio(vwrite, fd, mlen, sizeof(mlen)) <= 0)
+       if (atomicio(vwrite, fd, mlen, sizeof(mlen)) != sizeof(mlen))
                fatal("Couldn't send packet: %s", strerror(errno));
 
-       if (atomicio(vwrite, fd, buffer_ptr(m), buffer_len(m)) <= 0)
+       if (atomicio(vwrite, fd, buffer_ptr(m), buffer_len(m)) != buffer_len(m))
                fatal("Couldn't send packet: %s", strerror(errno));
 
        buffer_clear(m);
@@ -75,26 +76,27 @@ send_msg(int fd, Buffer *m)
 static void
 get_msg(int fd, Buffer *m)
 {
-       ssize_t len;
        u_int msg_len;
 
        buffer_append_space(m, 4);
-       len = atomicio(read, fd, buffer_ptr(m), 4);
-       if (len == 0)
-               fatal("Connection closed");
-       else if (len == -1)
-               fatal("Couldn't read packet: %s", strerror(errno));
+       if (atomicio(read, fd, buffer_ptr(m), 4) != 4) {
+               if (errno == EPIPE)
+                       fatal("Connection closed");
+               else
+                       fatal("Couldn't read packet: %s", strerror(errno));
+       }
 
        msg_len = buffer_get_int(m);
        if (msg_len > MAX_MSG_LENGTH)
                fatal("Received message too long %u", msg_len);
 
        buffer_append_space(m, msg_len);
-       len = atomicio(read, fd, buffer_ptr(m), msg_len);
-       if (len == 0)
-               fatal("Connection closed");
-       else if (len == -1)
-               fatal("Read packet: %s", strerror(errno));
+       if (atomicio(read, fd, buffer_ptr(m), msg_len) != msg_len) {
+               if (errno == EPIPE)
+                       fatal("Connection closed");
+               else
+                       fatal("Read packet: %s", strerror(errno));
+       }
 }
 
 static void
@@ -171,6 +173,7 @@ get_handle(int fd, u_int expected_id, u_int *len)
                int status = buffer_get_int(&msg);
 
                error("Couldn't get handle: %s", fx2txt(status));
+               buffer_free(&msg);
                return(NULL);
        } else if (type != SSH2_FXP_HANDLE)
                fatal("Expected SSH2_FXP_HANDLE(%u) packet, got %u",
@@ -205,6 +208,7 @@ get_decode_stat(int fd, u_int expected_id, int quiet)
                        debug("Couldn't stat remote file: %s", fx2txt(status));
                else
                        error("Couldn't stat remote file: %s", fx2txt(status));
+               buffer_free(&msg);
                return(NULL);
        } else if (type != SSH2_FXP_ATTRS) {
                fatal("Expected SSH2_FXP_ATTRS(%u) packet, got %u",
@@ -330,7 +334,7 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
                (*dir)[0] = NULL;
        }
 
-       for (;;) {
+       for (; !interrupted;) {
                int count;
 
                id = expected_id = conn->msg_id++;
@@ -407,6 +411,13 @@ do_lsreaddir(struct sftp_conn *conn, char *path, int printflag,
        do_close(conn, handle, handle_len);
        xfree(handle);
 
+       /* Don't return partial matches on interrupt */
+       if (interrupted && dir != NULL && *dir != NULL) {
+               free_sftp_dirents(*dir);
+               *dir = xmalloc(sizeof(**dir));
+               **dir = NULL;
+       }
+
        return(0);
 }
 
@@ -812,6 +823,16 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
                char *data;
                u_int len;
 
+               /*
+                * Simulate EOF on interrupt: stop sending new requests and
+                * allow outstanding requests to drain gracefully
+                */
+               if (interrupted) {
+                       if (num_req == 0) /* If we haven't started yet... */
+                               break;
+                       max_req = 0;
+               }
+
                /* Send some more requests */
                while (num_req < max_req) {
                        debug3("Request range %llu -> %llu (%d/%d)",
@@ -836,7 +857,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
                debug3("Received reply T:%u I:%u R:%d", type, id, max_req);
 
                /* Find the request in our queue */
-               for(req = TAILQ_FIRST(&requests);
+               for (req = TAILQ_FIRST(&requests);
                    req != NULL && req->id != id;
                    req = TAILQ_NEXT(req, tq))
                        ;
@@ -899,8 +920,7 @@ do_download(struct sftp_conn *conn, char *remote_path, char *local_path,
                                            (unsigned long long)offset,
                                            num_req);
                                        max_req = 1;
-                               }
-                               else if (max_req < conn->num_requests + 1) {
+                               } else if (max_req <= conn->num_requests) {
                                        ++max_req;
                                }
                        }
@@ -975,7 +995,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
                TAILQ_ENTRY(outstanding_ack) tq;
        };
        TAILQ_HEAD(ackhead, outstanding_ack) acks;
-       struct outstanding_ack *ack;
+       struct outstanding_ack *ack = NULL;
 
        TAILQ_INIT(&acks);
 
@@ -1036,10 +1056,14 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
                int len;
 
                /*
-                * Can't use atomicio here because it returns 0 on EOF, thus losing
-                * the last block of the file
+                * Can't use atomicio here because it returns 0 on EOF,
+                * thus losing the last block of the file.
+                * Simulate an EOF on interrupt, allowing ACKs from the
+                * server to drain.
                 */
-               do
+               if (interrupted)
+                       len = 0;
+               else do
                        len = read(local_fd, data, conn->transfer_buflen);
                while ((len == -1) && (errno == EINTR || errno == EAGAIN));
 
@@ -1086,7 +1110,7 @@ do_upload(struct sftp_conn *conn, char *local_path, char *remote_path,
                        debug3("SSH2_FXP_STATUS %d", status);
 
                        /* Find the request in our queue */
-                       for(ack = TAILQ_FIRST(&acks);
+                       for (ack = TAILQ_FIRST(&acks);
                            ack != NULL && ack->id != r_id;
                            ack = TAILQ_NEXT(ack, tq))
                                ;
This page took 0.043608 seconds and 4 git commands to generate.