summaryrefslogtreecommitdiff
path: root/scp.c
diff options
context:
space:
mode:
Diffstat (limited to 'scp.c')
-rw-r--r--scp.c116
1 files changed, 85 insertions, 31 deletions
diff --git a/scp.c b/scp.c
index 5d9e4bc29..e2eee035d 100644
--- a/scp.c
+++ b/scp.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: scp.c,v 1.160 2007/08/06 19:16:06 sobrado Exp $ */ 1/* $OpenBSD: scp.c,v 1.163 2008/06/13 18:55:22 dtucker Exp $ */
2/* 2/*
3 * scp - secure remote copy. This is basically patched BSD rcp which 3 * scp - secure remote copy. This is basically patched BSD rcp which
4 * uses ssh to do the data transfer (instead of using rcmd). 4 * uses ssh to do the data transfer (instead of using rcmd).
@@ -78,6 +78,13 @@
78#ifdef HAVE_SYS_STAT_H 78#ifdef HAVE_SYS_STAT_H
79# include <sys/stat.h> 79# include <sys/stat.h>
80#endif 80#endif
81#ifdef HAVE_POLL_H
82#include <poll.h>
83#else
84# ifdef HAVE_SYS_POLL_H
85# include <sys/poll.h>
86# endif
87#endif
81#ifdef HAVE_SYS_TIME_H 88#ifdef HAVE_SYS_TIME_H
82# include <sys/time.h> 89# include <sys/time.h>
83#endif 90#endif
@@ -109,6 +116,8 @@
109 116
110extern char *__progname; 117extern char *__progname;
111 118
119#define COPY_BUFLEN 16384
120
112int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout); 121int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
113 122
114void bwlimit(int); 123void bwlimit(int);
@@ -290,6 +299,7 @@ void sink(int, char *[]);
290void source(int, char *[]); 299void source(int, char *[]);
291void tolocal(int, char *[]); 300void tolocal(int, char *[]);
292void toremote(char *, int, char *[]); 301void toremote(char *, int, char *[]);
302size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *);
293void usage(void); 303void usage(void);
294 304
295int 305int
@@ -449,6 +459,43 @@ main(int argc, char **argv)
449 exit(errs != 0); 459 exit(errs != 0);
450} 460}
451 461
462/*
463 * atomicio-like wrapper that also applies bandwidth limits and updates
464 * the progressmeter counter.
465 */
466size_t
467scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c)
468{
469 u_char *p = (u_char *)_p;
470 size_t offset;
471 ssize_t r;
472 struct pollfd pfd;
473
474 pfd.fd = fd;
475 pfd.events = f == read ? POLLIN : POLLOUT;
476 for (offset = 0; offset < l;) {
477 r = f(fd, p + offset, l - offset);
478 if (r == 0) {
479 errno = EPIPE;
480 return offset;
481 }
482 if (r < 0) {
483 if (errno == EINTR)
484 continue;
485 if (errno == EAGAIN || errno == EWOULDBLOCK) {
486 (void)poll(&pfd, 1, -1); /* Ignore errors */
487 continue;
488 }
489 return offset;
490 }
491 offset += (size_t)r;
492 *c += (off_t)r;
493 if (limit_rate)
494 bwlimit(r);
495 }
496 return offset;
497}
498
452void 499void
453toremote(char *targ, int argc, char **argv) 500toremote(char *targ, int argc, char **argv)
454{ 501{
@@ -590,8 +637,8 @@ source(int argc, char **argv)
590 struct stat stb; 637 struct stat stb;
591 static BUF buffer; 638 static BUF buffer;
592 BUF *bp; 639 BUF *bp;
593 off_t i, amt, statbytes; 640 off_t i, statbytes;
594 size_t result; 641 size_t amt;
595 int fd = -1, haderr, indx; 642 int fd = -1, haderr, indx;
596 char *last, *name, buf[2048], encname[MAXPATHLEN]; 643 char *last, *name, buf[2048], encname[MAXPATHLEN];
597 int len; 644 int len;
@@ -612,6 +659,10 @@ source(int argc, char **argv)
612syserr: run_err("%s: %s", name, strerror(errno)); 659syserr: run_err("%s: %s", name, strerror(errno));
613 goto next; 660 goto next;
614 } 661 }
662 if (stb.st_size < 0) {
663 run_err("%s: %s", name, "Negative file size");
664 goto next;
665 }
615 unset_nonblock(fd); 666 unset_nonblock(fd);
616 switch (stb.st_mode & S_IFMT) { 667 switch (stb.st_mode & S_IFMT) {
617 case S_IFREG: 668 case S_IFREG:
@@ -637,8 +688,14 @@ syserr: run_err("%s: %s", name, strerror(errno));
637 * versions expecting microseconds. 688 * versions expecting microseconds.
638 */ 689 */
639 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n", 690 (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
640 (u_long) stb.st_mtime, 691 (u_long) (stb.st_mtime < 0 ? 0 : stb.st_mtime),
641 (u_long) stb.st_atime); 692 (u_long) (stb.st_atime < 0 ? 0 : stb.st_atime));
693 if (verbose_mode) {
694 fprintf(stderr, "File mtime %ld atime %ld\n",
695 (long)stb.st_mtime, (long)stb.st_atime);
696 fprintf(stderr, "Sending file timestamps: %s",
697 buf);
698 }
642 (void) atomicio(vwrite, remout, buf, strlen(buf)); 699 (void) atomicio(vwrite, remout, buf, strlen(buf));
643 if (response() < 0) 700 if (response() < 0)
644 goto next; 701 goto next;
@@ -653,7 +710,7 @@ syserr: run_err("%s: %s", name, strerror(errno));
653 (void) atomicio(vwrite, remout, buf, strlen(buf)); 710 (void) atomicio(vwrite, remout, buf, strlen(buf));
654 if (response() < 0) 711 if (response() < 0)
655 goto next; 712 goto next;
656 if ((bp = allocbuf(&buffer, fd, 2048)) == NULL) { 713 if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
657next: if (fd != -1) { 714next: if (fd != -1) {
658 (void) close(fd); 715 (void) close(fd);
659 fd = -1; 716 fd = -1;
@@ -662,27 +719,25 @@ next: if (fd != -1) {
662 } 719 }
663 if (showprogress) 720 if (showprogress)
664 start_progress_meter(curfile, stb.st_size, &statbytes); 721 start_progress_meter(curfile, stb.st_size, &statbytes);
665 /* Keep writing after an error so that we stay sync'd up. */ 722 set_nonblock(remout);
666 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) { 723 for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
667 amt = bp->cnt; 724 amt = bp->cnt;
668 if (i + amt > stb.st_size) 725 if (i + (off_t)amt > stb.st_size)
669 amt = stb.st_size - i; 726 amt = stb.st_size - i;
670 if (!haderr) { 727 if (!haderr) {
671 result = atomicio(read, fd, bp->buf, amt); 728 if (atomicio(read, fd, bp->buf, amt) != amt)
672 if (result != amt)
673 haderr = errno; 729 haderr = errno;
674 } 730 }
675 if (haderr) 731 /* Keep writing after error to retain sync */
676 (void) atomicio(vwrite, remout, bp->buf, amt); 732 if (haderr) {
677 else { 733 (void)atomicio(vwrite, remout, bp->buf, amt);
678 result = atomicio(vwrite, remout, bp->buf, amt); 734 continue;
679 if (result != amt)
680 haderr = errno;
681 statbytes += result;
682 } 735 }
683 if (limit_rate) 736 if (scpio(vwrite, remout, bp->buf, amt,
684 bwlimit(amt); 737 &statbytes) != amt)
738 haderr = errno;
685 } 739 }
740 unset_nonblock(remout);
686 if (showprogress) 741 if (showprogress)
687 stop_progress_meter(); 742 stop_progress_meter();
688 743
@@ -788,10 +843,10 @@ bwlimit(int amount)
788 thresh /= 2; 843 thresh /= 2;
789 if (thresh < 2048) 844 if (thresh < 2048)
790 thresh = 2048; 845 thresh = 2048;
791 } else if (bwend.tv_usec < 100) { 846 } else if (bwend.tv_usec < 10000) {
792 thresh *= 2; 847 thresh *= 2;
793 if (thresh > 32768) 848 if (thresh > COPY_BUFLEN * 4)
794 thresh = 32768; 849 thresh = COPY_BUFLEN * 4;
795 } 850 }
796 851
797 TIMEVAL_TO_TIMESPEC(&bwend, &ts); 852 TIMEVAL_TO_TIMESPEC(&bwend, &ts);
@@ -982,7 +1037,7 @@ bad: run_err("%s: %s", np, strerror(errno));
982 continue; 1037 continue;
983 } 1038 }
984 (void) atomicio(vwrite, remout, "", 1); 1039 (void) atomicio(vwrite, remout, "", 1);
985 if ((bp = allocbuf(&buffer, ofd, 4096)) == NULL) { 1040 if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
986 (void) close(ofd); 1041 (void) close(ofd);
987 continue; 1042 continue;
988 } 1043 }
@@ -992,26 +1047,24 @@ bad: run_err("%s: %s", np, strerror(errno));
992 statbytes = 0; 1047 statbytes = 0;
993 if (showprogress) 1048 if (showprogress)
994 start_progress_meter(curfile, size, &statbytes); 1049 start_progress_meter(curfile, size, &statbytes);
995 for (count = i = 0; i < size; i += 4096) { 1050 set_nonblock(remin);
996 amt = 4096; 1051 for (count = i = 0; i < size; i += bp->cnt) {
1052 amt = bp->cnt;
997 if (i + amt > size) 1053 if (i + amt > size)
998 amt = size - i; 1054 amt = size - i;
999 count += amt; 1055 count += amt;
1000 do { 1056 do {
1001 j = atomicio(read, remin, cp, amt); 1057 j = scpio(read, remin, cp, amt, &statbytes);
1002 if (j == 0) { 1058 if (j == 0) {
1003 run_err("%s", j ? strerror(errno) : 1059 run_err("%s", j != EPIPE ?
1060 strerror(errno) :
1004 "dropped connection"); 1061 "dropped connection");
1005 exit(1); 1062 exit(1);
1006 } 1063 }
1007 amt -= j; 1064 amt -= j;
1008 cp += j; 1065 cp += j;
1009 statbytes += j;
1010 } while (amt > 0); 1066 } while (amt > 0);
1011 1067
1012 if (limit_rate)
1013 bwlimit(4096);
1014
1015 if (count == bp->cnt) { 1068 if (count == bp->cnt) {
1016 /* Keep reading so we stay sync'd up. */ 1069 /* Keep reading so we stay sync'd up. */
1017 if (wrerr == NO) { 1070 if (wrerr == NO) {
@@ -1025,6 +1078,7 @@ bad: run_err("%s: %s", np, strerror(errno));
1025 cp = bp->buf; 1078 cp = bp->buf;
1026 } 1079 }
1027 } 1080 }
1081 unset_nonblock(remin);
1028 if (showprogress) 1082 if (showprogress)
1029 stop_progress_meter(); 1083 stop_progress_meter();
1030 if (count != 0 && wrerr == NO && 1084 if (count != 0 && wrerr == NO &&