Minor fix in usage message
[u/mdw/putty] / scp.c
diff --git a/scp.c b/scp.c
index 53cb60a..e2a9cf3 100644 (file)
--- a/scp.c
+++ b/scp.c
@@ -178,14 +178,13 @@ int from_backend(void *frontend, int is_stderr, const char *data, int datalen)
     unsigned char *p = (unsigned char *) data;
     unsigned len = (unsigned) datalen;
 
-    assert(len > 0);
-
     /*
      * stderr data is just spouted to local stderr and otherwise
      * ignored.
      */
     if (is_stderr) {
-       fwrite(data, 1, len, stderr);
+       if (len > 0)
+           fwrite(data, 1, len, stderr);
        return 0;
     }
 
@@ -195,7 +194,7 @@ int from_backend(void *frontend, int is_stderr, const char *data, int datalen)
     if (!outptr)
        return 0;
 
-    if (outlen > 0) {
+    if ((outlen > 0) && (len > 0)) {
        unsigned used = outlen;
        if (used > len)
            used = len;
@@ -291,7 +290,7 @@ static void bump(char *fmt, ...)
     if (back != NULL && back->socket(backhandle) != NULL) {
        char ch;
        back->special(backhandle, TS_EOF);
-       ssh_scp_recv(&ch, 1);
+       ssh_scp_recv((unsigned char *) &ch, 1);
     }
 
     if (gui_mode)
@@ -456,7 +455,7 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
     pct = (int) (100 * (done * 1.0 / size));
 
     if (gui_mode) {
-       gui_update_stats(name, size, pct, elap, done, eta, 
+       gui_update_stats(name, size, pct, elap, done, eta,
                         (unsigned long) ratebs);
     } else {
        len = printf("\r%-25.25s | %10ld kB | %5.1f kB/s | ETA: %8s | %3d%%",
@@ -467,6 +466,8 @@ static void print_stats(char *name, unsigned long size, unsigned long done,
 
        if (done == size)
            printf("\n");
+
+       fflush(stdout);
     }
 }
 
@@ -530,7 +531,7 @@ static int response(void)
     char ch, resp, rbuf[2048];
     int p;
 
-    if (ssh_scp_recv(&resp, 1) <= 0)
+    if (ssh_scp_recv((unsigned char *) &resp, 1) <= 0)
        bump("Lost connection");
 
     p = 0;
@@ -543,7 +544,7 @@ static int response(void)
       case 1:                         /* error */
       case 2:                         /* fatal error */
        do {
-           if (ssh_scp_recv(&ch, 1) <= 0)
+           if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0)
                bump("Protocol error: Lost connection");
            rbuf[p++] = ch;
        } while (p < sizeof(rbuf) && ch != '\n');
@@ -559,11 +560,11 @@ static int response(void)
 
 int sftp_recvdata(char *buf, int len)
 {
-    return ssh_scp_recv(buf, len);
+    return ssh_scp_recv((unsigned char *) buf, len);
 }
 int sftp_senddata(char *buf, int len)
 {
-    back->send(backhandle, (unsigned char *) buf, len);
+    back->send(backhandle, buf, len);
     return 1;
 }
 
@@ -673,6 +674,7 @@ static int scp_sftp_preserve, scp_sftp_recursive;
 static unsigned long scp_sftp_mtime, scp_sftp_atime;
 static int scp_has_times;
 static struct fxp_handle *scp_sftp_filehandle;
+static struct fxp_xfer *scp_sftp_xfer;
 static uint64 scp_sftp_fileoffset;
 
 void scp_source_setup(char *target, int shouldbedir)
@@ -767,6 +769,8 @@ int scp_send_filename(char *name, unsigned long size, int modes)
            return 1;
        }
        scp_sftp_fileoffset = uint64_make(0, 0);
+       scp_sftp_xfer = xfer_upload_init(scp_sftp_filehandle,
+                                        scp_sftp_fileoffset);
        sfree(fullname);
        return 0;
     } else {
@@ -784,23 +788,23 @@ int scp_send_filedata(char *data, int len)
     if (using_sftp) {
        int ret;
        struct sftp_packet *pktin;
-       struct sftp_request *req, *rreq;
 
        if (!scp_sftp_filehandle) {
            return 1;
        }
 
-       sftp_register(req = fxp_write_send(scp_sftp_filehandle,
-                                          data, scp_sftp_fileoffset, len));
-       rreq = sftp_find_request(pktin = sftp_recv());
-       assert(rreq == req);
-       ret = fxp_write_recv(pktin, rreq);
-
-       if (!ret) {
-           tell_user(stderr, "error while writing: %s\n", fxp_error());
-           errs++;
-           return 1;
+       while (!xfer_upload_ready(scp_sftp_xfer)) {
+           pktin = sftp_recv();
+           ret = xfer_upload_gotpkt(scp_sftp_xfer, pktin);
+           if (!ret) {
+               tell_user(stderr, "error while writing: %s\n", fxp_error());
+               errs++;
+               return 1;
+           }
        }
+
+       xfer_upload_data(scp_sftp_xfer, data, len);
+
        scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, len);
        return 0;
     } else {
@@ -830,6 +834,12 @@ int scp_send_finish(void)
        struct sftp_request *req, *rreq;
        int ret;
 
+       while (!xfer_done(scp_sftp_xfer)) {
+           pktin = sftp_recv();
+           xfer_upload_gotpkt(scp_sftp_xfer, pktin);
+       }
+       xfer_cleanup(scp_sftp_xfer);
+
        if (!scp_sftp_filehandle) {
            return 1;
        }
@@ -1310,14 +1320,14 @@ int scp_get_sink_action(struct scp_sink_action *act)
        bufsize = 0;
 
        while (!done) {
-           if (ssh_scp_recv(&ch, 1) <= 0)
+           if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0)
                return 1;
            if (ch == '\n')
                bump("Protocol error: Unexpected newline");
            i = 0;
            action = ch;
            do {
-               if (ssh_scp_recv(&ch, 1) <= 0)
+               if (ssh_scp_recv((unsigned char *) &ch, 1) <= 0)
                    bump("Lost connection");
                if (i >= bufsize) {
                    bufsize = i + 128;
@@ -1388,6 +1398,8 @@ int scp_accept_filexfer(void)
            return 1;
        }
        scp_sftp_fileoffset = uint64_make(0, 0);
+       scp_sftp_xfer = xfer_download_init(scp_sftp_filehandle,
+                                          scp_sftp_fileoffset);
        sfree(scp_sftp_currentname);
        return 0;
     } else {
@@ -1400,28 +1412,37 @@ int scp_recv_filedata(char *data, int len)
 {
     if (using_sftp) {
        struct sftp_packet *pktin;
-       struct sftp_request *req, *rreq;
-       int actuallen;
+       int ret, actuallen;
+       void *vbuf;
 
-       sftp_register(req = fxp_read_send(scp_sftp_filehandle,
-                                         scp_sftp_fileoffset, len));
-       rreq = sftp_find_request(pktin = sftp_recv());
-       assert(rreq == req);
-       actuallen = fxp_read_recv(pktin, rreq, data, len);
+       xfer_download_queue(scp_sftp_xfer);
+       pktin = sftp_recv();
+       ret = xfer_download_gotpkt(scp_sftp_xfer, pktin);
 
-       if (actuallen == -1 && fxp_error_type() != SSH_FX_EOF) {
+       if (ret < 0) {
            tell_user(stderr, "pscp: error while reading: %s", fxp_error());
            errs++;
            return -1;
        }
-       if (actuallen < 0)
+
+       if (xfer_download_data(scp_sftp_xfer, &vbuf, &actuallen)) {
+           /*
+            * This assertion relies on the fact that the natural
+            * block size used in the xfer manager is at most that
+            * used in this module. I don't like crossing layers in
+            * this way, but it'll do for now.
+            */
+           assert(actuallen <= len);
+           memcpy(data, vbuf, actuallen);
+           sfree(vbuf);
+       } else
            actuallen = 0;
 
        scp_sftp_fileoffset = uint64_add32(scp_sftp_fileoffset, actuallen);
 
        return actuallen;
     } else {
-       return ssh_scp_recv(data, len);
+       return ssh_scp_recv((unsigned char *) data, len);
     }
 }
 
@@ -1431,6 +1452,23 @@ int scp_finish_filerecv(void)
        struct sftp_packet *pktin;
        struct sftp_request *req, *rreq;
 
+       /*
+        * Ensure that xfer_done() will work correctly, so we can
+        * clean up any outstanding requests from the file
+        * transfer.
+        */
+       xfer_set_error(scp_sftp_xfer);
+       while (!xfer_done(scp_sftp_xfer)) {
+           void *vbuf;
+           int len;
+
+           pktin = sftp_recv();
+           xfer_download_gotpkt(scp_sftp_xfer, pktin);
+           if (xfer_download_data(scp_sftp_xfer, &vbuf, &len))
+               sfree(vbuf);
+       }
+       xfer_cleanup(scp_sftp_xfer);
+
        sftp_register(req = fxp_close_send(scp_sftp_filehandle));
        rreq = sftp_find_request(pktin = sftp_recv());
        assert(rreq == req);
@@ -1711,7 +1749,7 @@ static void sink(char *targ, char *src)
            }
 
            if (targ[0] != '\0')
-               destfname = dupcat(targ, "\\", striptarget, NULL);
+               destfname = dir_file_cat(targ, striptarget);
            else
                destfname = dupstr(striptarget);
        } else {
@@ -1996,7 +2034,7 @@ static void get_dir_list(int argc, char *argv[])
     if (using_sftp) {
        scp_sftp_listdir(src);
     } else {
-       while (ssh_scp_recv(&c, 1) > 0)
+       while (ssh_scp_recv((unsigned char *) &c, 1) > 0)
            tell_char(stdout, c);
     }
 }
@@ -2011,7 +2049,7 @@ static void usage(void)
     printf("Usage: pscp [options] [user@]host:source target\n");
     printf
        ("       pscp [options] source [source...] [user@]host:target\n");
-    printf("       pscp [options] -ls user@host:filespec\n");
+    printf("       pscp [options] -ls [user@]host:filespec\n");
     printf("Options:\n");
     printf("  -p        preserve file attributes\n");
     printf("  -q        quiet, don't show statistics\n");
@@ -2133,13 +2171,19 @@ int psftp_main(int argc, char *argv[])
     if (back != NULL && back->socket(backhandle) != NULL) {
        char ch;
        back->special(backhandle, TS_EOF);
-       ssh_scp_recv(&ch, 1);
+       ssh_scp_recv((unsigned char *) &ch, 1);
     }
     random_save_seed();
 
     if (gui_mode)
        gui_send_errcount(list, errs);
 
+    cmdline_cleanup();
+    console_provide_logctx(NULL);
+    back->free(backhandle);
+    backhandle = NULL;
+    back = NULL;
+    sk_cleanup();
     return (errs == 0 ? 0 : 1);
 }