- djm@cvs.openbsd.org 2004/05/19 12:17:33
     [sftp-client.c sftp.c]
     gracefully abort transfers on receipt of SIGINT, also ignore SIGINT while
     waiting for a command; ok markus@
diff --git a/sftp-client.c b/sftp-client.c
index bf2eb43..6dcd5de 100644
--- a/sftp-client.c
+++ b/sftp-client.c
@@ -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.49 2004/05/19 12:17:33 djm Exp $");
 
 #include "openbsd-compat/sys-queue.h"
 
@@ -36,6 +36,7 @@
 #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 */
@@ -330,7 +331,7 @@
 		(*dir)[0] = NULL;
 	}
 
-	for (;;) {
+	for (; !interrupted;) {
 		int count;
 
 		id = expected_id = conn->msg_id++;
@@ -407,6 +408,13 @@
 	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 +820,16 @@
 		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)",
@@ -899,8 +917,7 @@
 					    (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;
 				}
 			}
@@ -1036,10 +1053,14 @@
 		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));