]> andersk Git - gssapi-openssh.git/blobdiff - openssh/scp.c
The man2html from jbasney on pkilab2 works whereas the standard one doesn't.
[gssapi-openssh.git] / openssh / scp.c
index e1933b1c7cd23049087645b9fb7dcfe809b65413..25d75971142eec94f654070899f5539d8b37cb59 100644 (file)
@@ -1,4 +1,4 @@
-/* $OpenBSD: scp.c,v 1.160 2007/08/06 19:16:06 sobrado Exp $ */
+/* $OpenBSD: scp.c,v 1.164 2008/10/10 04:55:16 stevesk Exp $ */
 /*
  * scp - secure remote copy.  This is basically patched BSD rcp which
  * uses ssh to do the data transfer (instead of using rcmd).
 #ifdef HAVE_SYS_STAT_H
 # include <sys/stat.h>
 #endif
+#ifdef HAVE_POLL_H
+#include <poll.h>
+#else
+# ifdef HAVE_SYS_POLL_H
+#  include <sys/poll.h>
+# endif
+#endif
 #ifdef HAVE_SYS_TIME_H
 # include <sys/time.h>
 #endif
 
 extern char *__progname;
 
+#define COPY_BUFLEN    16384
+
 int do_cmd(char *host, char *remuser, char *cmd, int *fdin, int *fdout);
 
 void bwlimit(int);
@@ -282,6 +291,7 @@ void sink(int, char *[]);
 void source(int, char *[]);
 void tolocal(int, char *[]);
 void toremote(char *, int, char *[]);
+size_t scpio(ssize_t (*)(int, void *, size_t), int, void *, size_t, off_t *);
 void usage(void);
 
 int
@@ -321,8 +331,8 @@ main(int argc, char **argv)
                case '4':
                case '6':
                case 'C':
-                        addargs(&args, "-%c", ch);
-                        break;
+                       addargs(&args, "-%c", ch);
+                       break;
                case 'o':
                case 'c':
                case 'i':
@@ -424,7 +434,7 @@ main(int argc, char **argv)
        }
        /*
         * Finally check the exit status of the ssh process, if one was forked
-        * and no error has occured yet
+        * and no error has occurred yet
         */
        if (do_cmd_pid != -1 && errs == 0) {
                if (remin != -1)
@@ -441,6 +451,43 @@ main(int argc, char **argv)
        exit(errs != 0);
 }
 
+/*
+ * atomicio-like wrapper that also applies bandwidth limits and updates
+ * the progressmeter counter.
+ */
+size_t
+scpio(ssize_t (*f)(int, void *, size_t), int fd, void *_p, size_t l, off_t *c)
+{
+       u_char *p = (u_char *)_p;
+       size_t offset;
+       ssize_t r;
+       struct pollfd pfd;
+
+       pfd.fd = fd;
+       pfd.events = f == read ? POLLIN : POLLOUT;
+       for (offset = 0; offset < l;) {
+               r = f(fd, p + offset, l - offset);
+               if (r == 0) {
+                       errno = EPIPE;
+                       return offset;
+               }
+               if (r < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       if (errno == EAGAIN || errno == EWOULDBLOCK) {
+                               (void)poll(&pfd, 1, -1); /* Ignore errors */
+                               continue;
+                       }
+                       return offset;
+               }
+               offset += (size_t)r;
+               *c += (off_t)r;
+               if (limit_rate)
+                       bwlimit(r);
+       }
+       return offset;
+}
+
 void
 toremote(char *targ, int argc, char **argv)
 {
@@ -582,8 +629,8 @@ source(int argc, char **argv)
        struct stat stb;
        static BUF buffer;
        BUF *bp;
-       off_t i, amt, statbytes;
-       size_t result;
+       off_t i, statbytes;
+       size_t amt;
        int fd = -1, haderr, indx;
        char *last, *name, buf[16384], encname[MAXPATHLEN];
        int len;
@@ -604,6 +651,10 @@ source(int argc, char **argv)
 syserr:                        run_err("%s: %s", name, strerror(errno));
                        goto next;
                }
+               if (stb.st_size < 0) {
+                       run_err("%s: %s", name, "Negative file size");
+                       goto next;
+               }
                unset_nonblock(fd);
                switch (stb.st_mode & S_IFMT) {
                case S_IFREG:
@@ -629,8 +680,14 @@ syserr:                    run_err("%s: %s", name, strerror(errno));
                         * versions expecting microseconds.
                         */
                        (void) snprintf(buf, sizeof buf, "T%lu 0 %lu 0\n",
-                           (u_long) stb.st_mtime,
-                           (u_long) stb.st_atime);
+                           (u_long) (stb.st_mtime < 0 ? 0 : stb.st_mtime),
+                           (u_long) (stb.st_atime < 0 ? 0 : stb.st_atime));
+                       if (verbose_mode) {
+                               fprintf(stderr, "File mtime %ld atime %ld\n",
+                                   (long)stb.st_mtime, (long)stb.st_atime);
+                               fprintf(stderr, "Sending file timestamps: %s",
+                                   buf);
+                       }
                        (void) atomicio(vwrite, remout, buf, strlen(buf));
                        if (response() < 0)
                                goto next;
@@ -645,7 +702,7 @@ syserr:                     run_err("%s: %s", name, strerror(errno));
                (void) atomicio(vwrite, remout, buf, strlen(buf));
                if (response() < 0)
                        goto next;
-               if ((bp = allocbuf(&buffer, fd, sizeof(buf))) == NULL) {
+               if ((bp = allocbuf(&buffer, fd, COPY_BUFLEN)) == NULL) {
 next:                  if (fd != -1) {
                                (void) close(fd);
                                fd = -1;
@@ -654,27 +711,25 @@ next:                     if (fd != -1) {
                }
                if (showprogress)
                        start_progress_meter(curfile, stb.st_size, &statbytes);
-               /* Keep writing after an error so that we stay sync'd up. */
+               set_nonblock(remout);
                for (haderr = i = 0; i < stb.st_size; i += bp->cnt) {
                        amt = bp->cnt;
-                       if (i + amt > stb.st_size)
+                       if (i + (off_t)amt > stb.st_size)
                                amt = stb.st_size - i;
                        if (!haderr) {
-                               result = atomicio(read, fd, bp->buf, amt);
-                               if (result != amt)
+                               if (atomicio(read, fd, bp->buf, amt) != amt)
                                        haderr = errno;
                        }
-                       if (haderr)
-                               (void) atomicio(vwrite, remout, bp->buf, amt);
-                       else {
-                               result = atomicio(vwrite, remout, bp->buf, amt);
-                               if (result != amt)
-                                       haderr = errno;
-                               statbytes += result;
+                       /* Keep writing after error to retain sync */
+                       if (haderr) {
+                               (void)atomicio(vwrite, remout, bp->buf, amt);
+                               continue;
                        }
-                       if (limit_rate)
-                               bwlimit(amt);
+                       if (scpio(vwrite, remout, bp->buf, amt,
+                           &statbytes) != amt)
+                               haderr = errno;
                }
+               unset_nonblock(remout);
                if (showprogress)
                        stop_progress_meter();
 
@@ -780,10 +835,10 @@ bwlimit(int amount)
                        thresh /= 2;
                        if (thresh < 2048)
                                thresh = 2048;
-               } else if (bwend.tv_usec < 100) {
+               } else if (bwend.tv_usec < 10000) {
                        thresh *= 2;
-                       if (thresh > 32768)
-                               thresh = 32768;
+                       if (thresh > COPY_BUFLEN * 4)
+                               thresh = COPY_BUFLEN * 4;
                }
 
                TIMEVAL_TO_TIMESPEC(&bwend, &ts);
@@ -974,7 +1029,7 @@ bad:                       run_err("%s: %s", np, strerror(errno));
                        continue;
                }
                (void) atomicio(vwrite, remout, "", 1);
-               if ((bp = allocbuf(&buffer, ofd, sizeof(buf))) == NULL) {
+               if ((bp = allocbuf(&buffer, ofd, COPY_BUFLEN)) == NULL) {
                        (void) close(ofd);
                        continue;
                }
@@ -984,26 +1039,24 @@ bad:                     run_err("%s: %s", np, strerror(errno));
                statbytes = 0;
                if (showprogress)
                        start_progress_meter(curfile, size, &statbytes);
-               for (count = i = 0; i < size; i += sizeof(buf)) {
-                       amt = sizeof(buf);
+               set_nonblock(remin);
+               for (count = i = 0; i < size; i += bp->cnt) {
+                       amt = bp->cnt;
                        if (i + amt > size)
                                amt = size - i;
                        count += amt;
                        do {
-                               j = atomicio(read, remin, cp, amt);
+                               j = scpio(read, remin, cp, amt, &statbytes);
                                if (j == 0) {
-                                       run_err("%s", j ? strerror(errno) :
+                                       run_err("%s", j != EPIPE ?
+                                           strerror(errno) :
                                            "dropped connection");
                                        exit(1);
                                }
                                amt -= j;
                                cp += j;
-                               statbytes += j;
                        } while (amt > 0);
 
-                       if (limit_rate)
-                               bwlimit(sizeof(buf));
-
                        if (count == bp->cnt) {
                                /* Keep reading so we stay sync'd up. */
                                if (wrerr == NO) {
@@ -1017,6 +1070,7 @@ bad:                      run_err("%s: %s", np, strerror(errno));
                                cp = bp->buf;
                        }
                }
+               unset_nonblock(remin);
                if (showprogress)
                        stop_progress_meter();
                if (count != 0 && wrerr == NO &&
This page took 0.050258 seconds and 4 git commands to generate.