When giving authorisation errors from the proxy code in x11fwd.c,
[u/mdw/putty] / psftp.c
diff --git a/psftp.c b/psftp.c
index 6a4ba56..e0fbee8 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -16,6 +16,8 @@
 #include "sftp.h"
 #include "int64.h"
 
+const char *const appname = "PSFTP";
+
 /*
  * Since SFTP is a request-response oriented protocol, it requires
  * no buffer management: when we send data, we stop and wait for an
@@ -128,8 +130,12 @@ char *canonify(char *name)
        assert(rreq == req);
        canonname = fxp_realpath_recv(pktin, rreq);
 
-       if (!canonname)
-           return fullname;           /* even that failed; give up */
+       if (!canonname) {
+           /* Even that failed. Restore our best guess at the
+            * constructed filename and give up */
+           fullname[i] = '/';  /* restore slash and last component */
+           return fullname;
+       }
 
        /*
         * We have a canonical name for all but the last path
@@ -204,7 +210,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
     struct sftp_request *req, *rreq;
     struct fxp_xfer *xfer;
     uint64 offset;
-    FILE *fp;
+    WFile *file;
     int ret, shown_err = FALSE;
 
     /*
@@ -317,22 +323,24 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
             * If none of them exists, of course, we start at 0.
             */
            i = 0;
-           while (i < nnames) {
-               char *nextoutfname;
-               int ret;
-               if (outfname)
-                   nextoutfname = dir_file_cat(outfname,
-                                               ournames[i]->filename);
-               else
-                   nextoutfname = dupstr(ournames[i]->filename);
-               ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT);
-               sfree(nextoutfname);
-               if (ret)
-                   break;
-               i++;
-           }
-           if (i > 0)
-               i--;
+            if (restart) {
+                while (i < nnames) {
+                    char *nextoutfname;
+                    int ret;
+                    if (outfname)
+                        nextoutfname = dir_file_cat(outfname,
+                                                    ournames[i]->filename);
+                    else
+                        nextoutfname = dupstr(ournames[i]->filename);
+                    ret = (file_type(nextoutfname) == FILE_TYPE_NONEXISTENT);
+                    sfree(nextoutfname);
+                    if (ret)
+                        break;
+                    i++;
+                }
+                if (i > 0)
+                    i--;
+            }
 
            /*
             * Now we're ready to recurse. Starting at ournames[i]
@@ -381,17 +389,17 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
     fh = fxp_open_recv(pktin, rreq);
 
     if (!fh) {
-       printf("%s: %s\n", fname, fxp_error());
+       printf("%s: open for read: %s\n", fname, fxp_error());
        return 0;
     }
 
     if (restart) {
-       fp = fopen(outfname, "rb+");
+       file = open_existing_wfile(outfname, NULL);
     } else {
-       fp = fopen(outfname, "wb");
+       file = open_new_file(outfname);
     }
 
-    if (!fp) {
+    if (!file) {
        printf("local: unable to open %s\n", outfname);
 
        sftp_register(req = fxp_close_send(fh));
@@ -403,11 +411,22 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
     }
 
     if (restart) {
-       long posn;
-       fseek(fp, 0L, SEEK_END);
-       posn = ftell(fp);
-       printf("reget: restarting at file position %ld\n", posn);
-       offset = uint64_make(0, posn);
+       char decbuf[30];
+       if (seek_file(file, uint64_make(0,0) , FROM_END) == -1) {
+           close_wfile(file);
+           printf("reget: cannot restart %s - file too large\n",
+                  outfname);
+           sftp_register(req = fxp_close_send(fh));
+           rreq = sftp_find_request(pktin = sftp_recv());
+           assert(rreq == req);
+           fxp_close_recv(pktin, rreq);
+               
+           return 0;
+       }
+           
+       offset = get_file_posn(file);
+       uint64_decimal(offset, decbuf);
+       printf("reget: restarting at file position %s\n", decbuf);
     } else {
        offset = uint64_make(0, 0);
     }
@@ -442,11 +461,12 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
 
            wpos = 0;
            while (wpos < len) {
-               wlen = fwrite(buf + wpos, 1, len - wpos, fp);
+               wlen = write_to_file(file, buf + wpos, len - wpos);
                if (wlen <= 0) {
                    printf("error while writing local file\n");
                    ret = 0;
                    xfer_set_error(xfer);
+                   break;
                }
                wpos += wlen;
            }
@@ -461,7 +481,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
 
     xfer_cleanup(xfer);
 
-    fclose(fp);
+    close_wfile(file);
 
     sftp_register(req = fxp_close_send(fh));
     rreq = sftp_find_request(pktin = sftp_recv());
@@ -478,7 +498,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
     struct sftp_packet *pktin;
     struct sftp_request *req, *rreq;
     uint64 offset;
-    FILE *fp;
+    RFile *file;
     int ret, err, eof;
 
     /*
@@ -554,23 +574,25 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
         * If none of them exists, of course, we start at 0.
         */
        i = 0;
-       while (i < nnames) {
-           char *nextoutfname;
-           nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
-           sftp_register(req = fxp_stat_send(nextoutfname));
-           rreq = sftp_find_request(pktin = sftp_recv());
-           assert(rreq == req);
-           result = fxp_stat_recv(pktin, rreq, &attrs);
-           sfree(nextoutfname);
-           if (!result)
-               break;
-           i++;
-       }
-       if (i > 0)
-           i--;
+        if (restart) {
+            while (i < nnames) {
+                char *nextoutfname;
+                nextoutfname = dupcat(outfname, "/", ournames[i], NULL);
+                sftp_register(req = fxp_stat_send(nextoutfname));
+                rreq = sftp_find_request(pktin = sftp_recv());
+                assert(rreq == req);
+                result = fxp_stat_recv(pktin, rreq, &attrs);
+                sfree(nextoutfname);
+                if (!result)
+                    break;
+                i++;
+            }
+            if (i > 0)
+                i--;
+        }
 
-       /*
-        * Now we're ready to recurse. Starting at ournames[i]
+        /*
+         * Now we're ready to recurse. Starting at ournames[i]
         * and continuing on to the end of the list, we
         * construct a new source and target file name, and
         * call sftp_put_file again.
@@ -608,8 +630,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
        return 1;
     }
 
-    fp = fopen(fname, "rb");
-    if (!fp) {
+    file = open_existing_file(fname, NULL, NULL, NULL);
+    if (!file) {
        printf("local: unable to open %s\n", fname);
        return 0;
     }
@@ -624,7 +646,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
     fh = fxp_open_recv(pktin, rreq);
 
     if (!fh) {
-       printf("%s: %s\n", outfname, fxp_error());
+       close_rfile(file);
+       printf("%s: open for write: %s\n", outfname, fxp_error());
        return 0;
     }
 
@@ -639,22 +662,21 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
        ret = fxp_fstat_recv(pktin, rreq, &attrs);
 
        if (!ret) {
+           close_rfile(file);
            printf("read size of %s: %s\n", outfname, fxp_error());
            return 0;
        }
        if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) {
+           close_rfile(file);
            printf("read size of %s: size was not given\n", outfname);
            return 0;
        }
        offset = attrs.size;
        uint64_decimal(offset, decbuf);
        printf("reput: restarting at file position %s\n", decbuf);
-       if (uint64_compare(offset, uint64_make(0, LONG_MAX)) > 0) {
-           printf("reput: remote file is larger than we can deal with\n");
-           return 0;
-       }
-       if (fseek(fp, offset.lo, SEEK_SET) != 0)
-           fseek(fp, 0, SEEK_END);    /* *shrug* */
+
+       if (seek_file((WFile *)file, offset, FROM_START) != 0)
+           seek_file((WFile *)file, uint64_make(0,0), FROM_END);    /* *shrug* */
     } else {
        offset = uint64_make(0, 0);
     }
@@ -673,7 +695,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
        int len, ret;
 
        while (xfer_upload_ready(xfer) && !err && !eof) {
-           len = fread(buffer, 1, sizeof(buffer), fp);
+           len = read_from_file(file, buffer, sizeof(buffer));
            if (len == -1) {
                printf("error while reading local file\n");
                err = 1;
@@ -687,7 +709,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
        if (!xfer_done(xfer)) {
            pktin = sftp_recv();
            ret = xfer_upload_gotpkt(xfer, pktin);
-           if (!ret) {
+           if (ret <= 0 && !err) {
                printf("error while writing: %s\n", fxp_error());
                err = 1;
            }
@@ -701,7 +723,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
     assert(rreq == req);
     fxp_close_recv(pktin, rreq);
 
-    fclose(fp);
+    close_rfile(file);
 
     return ret;
 }
@@ -874,7 +896,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx)
        while ( (newname = sftp_wildcard_get_filename(swcm)) != NULL ) {
            cname = canonify(newname);
            if (!cname) {
-               printf("%s: %s\n", newname, fxp_error());
+               printf("%s: canonify: %s\n", newname, fxp_error());
                ret = 0;
            }
            matched = TRUE;
@@ -891,7 +913,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx)
     } else {
        cname = canonify(unwcfname);
        if (!cname) {
-           printf("%s: %s\n", filename, fxp_error());
+           printf("%s: canonify: %s\n", filename, fxp_error());
            ret = 0;
        }
        ret = func(ctx, cname);
@@ -945,7 +967,7 @@ int sftp_cmd_close(struct sftp_command *cmd)
        return 0;
     }
 
-    if (back != NULL && back->socket(backhandle) != NULL) {
+    if (back != NULL && back->connected(backhandle)) {
        char ch;
        back->special(backhandle, TS_EOF);
        sftp_recvdata(&ch, 1);
@@ -1007,7 +1029,7 @@ int sftp_cmd_ls(struct sftp_command *cmd)
 
     cdir = canonify(dir);
     if (!cdir) {
-       printf("%s: %s\n", dir, fxp_error());
+       printf("%s: canonify: %s\n", dir, fxp_error());
        sfree(unwcdir);
        return 0;
     }
@@ -1103,7 +1125,7 @@ int sftp_cmd_cd(struct sftp_command *cmd)
        dir = canonify(cmd->words[1]);
 
     if (!dir) {
-       printf("%s: %s\n", dir, fxp_error());
+       printf("%s: canonify: %s\n", dir, fxp_error());
        return 0;
     }
 
@@ -1214,7 +1236,7 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple)
            fname = canonify(origwfname);
 
            if (!fname) {
-               printf("%s: %s\n", origwfname, fxp_error());
+               printf("%s: canonify: %s\n", origwfname, fxp_error());
                sfree(unwcfname);
                return 0;
            }
@@ -1325,7 +1347,7 @@ int sftp_general_put(struct sftp_command *cmd, int restart, int multiple)
 
            outfname = canonify(origoutfname);
            if (!outfname) {
-               printf("%s: %s\n", origoutfname, fxp_error());
+               printf("%s: canonify: %s\n", origoutfname, fxp_error());
                if (wcm) {
                    sfree(wfname);
                    finish_wildcard_matching(wcm);
@@ -1388,7 +1410,7 @@ int sftp_cmd_mkdir(struct sftp_command *cmd)
     for (i = 1; i < cmd->nwords; i++) {
        dir = canonify(cmd->words[i]);
        if (!dir) {
-           printf("%s: %s\n", dir, fxp_error());
+           printf("%s: canonify: %s\n", dir, fxp_error());
            return 0;
        }
 
@@ -1536,7 +1558,7 @@ static int sftp_action_mv(void *vctx, char *srcfname)
        newname = dupcat(ctx->dstfname, "/", p, NULL);
        newcanon = canonify(newname);
        if (!newcanon) {
-           printf("%s: %s\n", newname, fxp_error());
+           printf("%s: canonify: %s\n", newname, fxp_error());
            sfree(newname);
            return 0;
        }
@@ -1583,7 +1605,7 @@ int sftp_cmd_mv(struct sftp_command *cmd)
 
     ctx->dstfname = canonify(cmd->words[cmd->nwords-1]);
     if (!ctx->dstfname) {
-       printf("%s: %s\n", ctx->dstfname, fxp_error());
+       printf("%s: canonify: %s\n", ctx->dstfname, fxp_error());
        return 0;
     }
 
@@ -2220,6 +2242,11 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
        cmd->words = sresize(cmd->words, cmd->wordssize, char *);
        cmd->words[0] = dupstr("!");
        cmd->words[1] = dupstr(p+1);
+    } else if (*p == '#') {
+       /*
+        * Special case: comment. Entire line is ignored.
+        */
+       cmd->nwords = cmd->wordssize = 0;
     } else {
 
        /*
@@ -2560,7 +2587,7 @@ int sftp_recvdata(char *buf, int len)
     }
 
     while (outlen > 0) {
-       if (ssh_sftp_loop_iteration() < 0)
+       if (back->exitcode(backhandle) >= 0 || ssh_sftp_loop_iteration() < 0)
            return 0;                  /* doom */
     }
 
@@ -2724,24 +2751,6 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
        strncpy(cfg.username, user, sizeof(cfg.username) - 1);
        cfg.username[sizeof(cfg.username) - 1] = '\0';
     }
-    if (!cfg.username[0]) {
-        /* FIXME: leave this to ssh.c? */
-        int ret;
-        prompts_t *p = new_prompts(NULL);
-        p->to_server = TRUE;
-        p->name = dupstr("SSH login name");
-        add_prompt(p, dupstr("login as: "), TRUE, lenof(cfg.username));
-        ret = get_userpass_input(p, NULL, 0);
-        assert(ret >= 0);
-        if (!ret) {
-            free_prompts(p);
-           fprintf(stderr, "psftp: no username, aborting\n");
-           cleanup_exit(1);
-       } else {
-            memcpy(cfg.username, p->prompts[0]->result, lenof(cfg.username));
-            free_prompts(p);
-       }
-    }
 
     if (portnumber)
        cfg.port = portnumber;
@@ -2754,6 +2763,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
     cfg.x11_forward = 0;
     cfg.agentfwd = 0;
     cfg.portfwd[0] = cfg.portfwd[1] = '\0';
+    cfg.ssh_simple = TRUE;
 
     /* Set up subsystem name. */
     strcpy(cfg.remote_cmd, "sftp");
@@ -2795,6 +2805,8 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
     back->provide_logctx(backhandle, logctx);
     console_provide_logctx(logctx);
     while (!back->sendok(backhandle)) {
+       if (back->exitcode(backhandle) >= 0)
+           return 1;
        if (ssh_sftp_loop_iteration() < 0) {
            fprintf(stderr, "ssh_init: error during SSH connection setup\n");
            return 1;
@@ -2920,7 +2932,7 @@ int psftp_main(int argc, char *argv[])
 
     do_sftp(mode, modeflags, batchfile);
 
-    if (back != NULL && back->socket(backhandle) != NULL) {
+    if (back != NULL && back->connected(backhandle)) {
        char ch;
        back->special(backhandle, TS_EOF);
        sftp_recvdata(&ch, 1);