]> asedeno.scripts.mit.edu Git - PuTTY.git/blobdiff - psftp.c
first pass
[PuTTY.git] / psftp.c
diff --git a/psftp.c b/psftp.c
index 26f24f9ce7f04da388e53cdd2ef0e3950c40311d..5394c1fbb9150007422c8f9d0b39da66ff8aa37e 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -68,7 +68,7 @@ struct sftp_packet *sftp_wait_for_reply(struct sftp_request *req)
  * canonification fails, at least fall back to returning a _valid_
  * pathname (though it may be ugly, eg /home/simon/../foobar).
  */
-char *canonify(char *name)
+char *canonify(const char *name)
 {
     char *fullname, *canonname;
     struct sftp_packet *pktin;
@@ -77,7 +77,7 @@ char *canonify(char *name)
     if (name[0] == '/') {
        fullname = dupstr(name);
     } else {
-       char *slash;
+       const char *slash;
        if (pwd[strlen(pwd) - 1] == '/')
            slash = "";
        else
@@ -169,30 +169,6 @@ char *canonify(char *name)
     }
 }
 
-/*
- * Return a pointer to the portion of str that comes after the last
- * slash (or backslash or colon, if `local' is TRUE).
- */
-static char *stripslashes(char *str, int local)
-{
-    char *p;
-
-    if (local) {
-        p = strchr(str, ':');
-        if (p) str = p+1;
-    }
-
-    p = strrchr(str, '/');
-    if (p) str = p+1;
-
-    if (local) {
-       p = strrchr(str, '\\');
-       if (p) str = p+1;
-    }
-
-    return str;
-}
-
 /*
  * qsort comparison routine for fxp_name structures. Sorts by real
  * file name.
@@ -457,7 +433,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
     xfer = xfer_download_init(fh, offset);
     while (!xfer_done(xfer)) {
        void *vbuf;
-       int ret, len;
+       int len;
        int wpos, wlen;
 
        xfer_download_queue(xfer);
@@ -468,6 +444,8 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
                printf("error while reading: %s\n", fxp_error());
                shown_err = TRUE;
            }
+            if (ret == INT_MIN)        /* pktin not even freed */
+                sfree(pktin);
             ret = 0;
        }
 
@@ -513,7 +491,7 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
     struct sftp_request *req;
     uint64 offset;
     RFile *file;
-    int ret, err, eof;
+    int err = 0, eof;
     struct fxp_attrs attrs;
     long permissions;
 
@@ -666,21 +644,21 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
     if (restart) {
        char decbuf[30];
        struct fxp_attrs attrs;
-       int ret;
+        int ret;
 
        req = fxp_fstat_send(fh);
         pktin = sftp_wait_for_reply(req);
        ret = fxp_fstat_recv(pktin, req, &attrs);
 
        if (!ret) {
-           close_rfile(file);
            printf("read size of %s: %s\n", outfname, fxp_error());
-           return 0;
+           err = 1;
+            goto cleanup;
        }
        if (!(attrs.flags & SSH_FILEXFER_ATTR_SIZE)) {
-           close_rfile(file);
            printf("read size of %s: size was not given\n", outfname);
-           return 0;
+           err = 1;
+            goto cleanup;
        }
        offset = attrs.size;
        uint64_decimal(offset, decbuf);
@@ -698,9 +676,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
      * FIXME: we can use FXP_FSTAT here to get the file size, and
      * thus put up a progress bar.
      */
-    ret = 1;
     xfer = xfer_upload_init(fh, offset);
-    err = eof = 0;
+    eof = 0;
     while ((!err && !eof) || !xfer_done(xfer)) {
        char buffer[4096];
        int len, ret;
@@ -720,22 +697,32 @@ 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 <= 0 && !err) {
-               printf("error while writing: %s\n", fxp_error());
-               err = 1;
+           if (ret <= 0) {
+                if (ret == INT_MIN)        /* pktin not even freed */
+                    sfree(pktin);
+                if (!err) {
+                    printf("error while writing: %s\n", fxp_error());
+                    err = 1;
+                }
            }
        }
     }
 
     xfer_cleanup(xfer);
 
+  cleanup:
     req = fxp_close_send(fh);
     pktin = sftp_wait_for_reply(req);
-    fxp_close_recv(pktin, req);
+    if (!fxp_close_recv(pktin, req)) {
+       if (!err) {
+           printf("error while closing: %s", fxp_error());
+           err = 1;
+       }
+    }
 
     close_rfile(file);
 
-    return ret;
+    return (err == 0) ? 1 : 0;
 }
 
 /* ----------------------------------------------------------------------
@@ -916,6 +903,7 @@ int wildcard_iterate(char *filename, int (*func)(void *, char *), void *ctx)
                printf("%s: canonify: %s\n", newname, fxp_error());
                ret = 0;
            }
+            sfree(newname);
            matched = TRUE;
            ret &= func(ctx, cname);
            sfree(cname);
@@ -1005,7 +993,8 @@ int sftp_cmd_ls(struct sftp_command *cmd)
     struct fxp_names *names;
     struct fxp_name **ournames;
     int nnames, namesize;
-    char *dir, *cdir, *unwcdir, *wildcard;
+    const char *dir;
+    char *cdir, *unwcdir, *wildcard;
     struct sftp_packet *pktin;
     struct sftp_request *req;
     int i;
@@ -1028,6 +1017,7 @@ int sftp_cmd_ls(struct sftp_command *cmd)
        char *tmpdir;
        int len, check;
 
+        sfree(unwcdir);
        wildcard = stripslashes(dir, 0);
        unwcdir = dupstr(dir);
        len = wildcard - dir;
@@ -1060,6 +1050,7 @@ int sftp_cmd_ls(struct sftp_command *cmd)
 
     if (dirh == NULL) {
        printf("Unable to open %s: %s\n", dir, fxp_error());
+       return 0;
     } else {
        nnames = namesize = 0;
        ournames = NULL;
@@ -1250,7 +1241,9 @@ int sftp_general_get(struct sftp_command *cmd, int restart, int multiple)
            fname = canonify(origwfname);
 
            if (!fname) {
+                sftp_finish_wildcard_matching(swcm);
                printf("%s: canonify: %s\n", origwfname, fxp_error());
+               sfree(origwfname);
                sfree(unwcfname);
                return 0;
            }
@@ -1892,7 +1885,7 @@ static int sftp_cmd_pling(struct sftp_command *cmd)
 static int sftp_cmd_help(struct sftp_command *cmd);
 
 static struct sftp_cmd_lookup {
-    char *name;
+    const char *name;
     /*
      * For help purposes, there are two kinds of command:
      * 
@@ -1906,8 +1899,8 @@ static struct sftp_cmd_lookup {
      *    contains the help that should double up for this command.
      */
     int listed;                               /* do we list this in primary help? */
-    char *shorthelp;
-    char *longhelp;
+    const char *shorthelp;
+    const char *longhelp;
     int (*obey) (struct sftp_command *);
 } sftp_lookup[] = {
     /*
@@ -2130,7 +2123,7 @@ static struct sftp_cmd_lookup {
     }
 };
 
-const struct sftp_cmd_lookup *lookup_command(char *name)
+const struct sftp_cmd_lookup *lookup_command(const char *name)
 {
     int i, j, k, cmp;
 
@@ -2226,6 +2219,7 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
        cmd->obey = sftp_cmd_quit;
        if ((mode == 0) || (modeflags & 1))
            printf("quit\n");
+        sfree(line);
        return cmd;                    /* eof */
     }
 
@@ -2378,7 +2372,7 @@ void do_sftp_cleanup()
     }
 }
 
-void do_sftp(int mode, int modeflags, char *batchfile)
+int do_sftp(int mode, int modeflags, char *batchfile)
 {
     FILE *fp;
     int ret;
@@ -2411,8 +2405,9 @@ void do_sftp(int mode, int modeflags, char *batchfile)
         fp = fopen(batchfile, "r");
         if (!fp) {
            printf("Fatal: unable to open %s\n", batchfile);
-           return;
+           return 1;
         }
+       ret = 0;
         while (1) {
            struct sftp_command *cmd;
            cmd = sftp_getcmd(fp, mode, modeflags);
@@ -2427,8 +2422,13 @@ void do_sftp(int mode, int modeflags, char *batchfile)
            }
         }
        fclose(fp);
-
+       /*
+        * In batch mode, and if exit on command failure is enabled,
+        * any command failure causes the whole of PSFTP to fail.
+        */
+       if (ret == 0 && !(modeflags & 2)) return 2;
     }
+    return 0;
 }
 
 /* ----------------------------------------------------------------------
@@ -2440,7 +2440,7 @@ static int verbose = 0;
 /*
  *  Print an error message and perform a fatal exit.
  */
-void fatalbox(char *fmt, ...)
+void fatalbox(const char *fmt, ...)
 {
     char *str, *str2;
     va_list ap;
@@ -2454,7 +2454,7 @@ void fatalbox(char *fmt, ...)
 
     cleanup_exit(1);
 }
-void modalfatalbox(char *fmt, ...)
+void modalfatalbox(const char *fmt, ...)
 {
     char *str, *str2;
     va_list ap;
@@ -2468,7 +2468,19 @@ void modalfatalbox(char *fmt, ...)
 
     cleanup_exit(1);
 }
-void connection_fatal(void *frontend, char *fmt, ...)
+void nonfatal(const char *fmt, ...)
+{
+    char *str, *str2;
+    va_list ap;
+    va_start(ap, fmt);
+    str = dupvprintf(fmt, ap);
+    str2 = dupcat("Error: ", str, "\n", NULL);
+    sfree(str);
+    va_end(ap);
+    fputs(str2, stderr);
+    sfree(str2);
+}
+void connection_fatal(void *frontend, const char *fmt, ...)
 {
     char *str, *str2;
     va_list ap;
@@ -2483,16 +2495,7 @@ void connection_fatal(void *frontend, char *fmt, ...)
     cleanup_exit(1);
 }
 
-void ldisc_send(void *handle, char *buf, int len, int interactive)
-{
-    /*
-     * This is only here because of the calls to ldisc_send(NULL,
-     * 0) in ssh.c. Nothing in PSFTP actually needs to use the
-     * ldisc as an ldisc. So if we get called with any real data, I
-     * want to know about it.
-     */
-    assert(len == 0);
-}
+void ldisc_echoedit_update(void *handle) { }
 
 /*
  * In psftp, all agent requests should be synchronous, so this is a
@@ -2622,6 +2625,10 @@ int sftp_senddata(char *buf, int len)
     back->send(backhandle, buf, len);
     return 1;
 }
+int sftp_sendbuffer(void)
+{
+    return back->sendbuffer(backhandle);
+}
 
 /*
  *  Short description of parameters.
@@ -2645,17 +2652,26 @@ static void usage(void)
     printf("  -1 -2     force use of particular SSH protocol version\n");
     printf("  -4 -6     force use of IPv4 or IPv6\n");
     printf("  -C        enable compression\n");
-    printf("  -i key    private key file for authentication\n");
+    printf("  -i key    private key file for user authentication\n");
     printf("  -noagent  disable use of Pageant\n");
     printf("  -agent    enable use of Pageant\n");
+    printf("  -hostkey aa:bb:cc:...\n");
+    printf("            manually specify a host key (may be repeated)\n");
     printf("  -batch    disable all interactive prompts\n");
+    printf("  -proxycmd command\n");
+    printf("            use 'command' as local proxy\n");
+    printf("  -sshlog file\n");
+    printf("  -sshrawlog file\n");
+    printf("            log protocol details to a file\n");
     cleanup_exit(1);
 }
 
 static void version(void)
 {
-  printf("psftp: %s\n", ver);
-  cleanup_exit(1);
+  char *buildinfo_text = buildinfo("\n");
+  printf("psftp: %s\n%s\n", ver, buildinfo_text);
+  sfree(buildinfo_text);
+  exit(0);
 }
 
 /*
@@ -2699,6 +2715,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
            /* Use `host' as a bare hostname. */
            conf_set_str(conf, CONF_host, host);
        }
+        conf_free(conf2);
     } else {
        /* Patch in hostname `host' to session details. */
        conf_set_str(conf, CONF_host, host);
@@ -2823,6 +2840,11 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
 
     back = &ssh_backend;
 
+    logctx = log_init(NULL, conf);
+    console_provide_logctx(logctx);
+
+    platform_psftp_pre_conn_setup();
+
     err = back->init(NULL, &backhandle, conf,
                     conf_get_str(conf, CONF_host),
                     conf_get_int(conf, CONF_port),
@@ -2832,9 +2854,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
        fprintf(stderr, "ssh_init: %s\n", err);
        return 1;
     }
-    logctx = log_init(NULL, conf);
     back->provide_logctx(backhandle, logctx);
-    console_provide_logctx(logctx);
     while (!back->sendok(backhandle)) {
        if (back->exitcode(backhandle) >= 0)
            return 1;
@@ -2850,7 +2870,7 @@ static int psftp_connect(char *userhost, char *user, int portnumber)
     return 0;
 }
 
-void cmdline_error(char *p, ...)
+void cmdline_error(const char *p, ...)
 {
     va_list ap;
     fprintf(stderr, "psftp: ");
@@ -2861,12 +2881,15 @@ void cmdline_error(char *p, ...)
     exit(1);
 }
 
+const int share_can_be_downstream = TRUE;
+const int share_can_be_upstream = FALSE;
+
 /*
  * Main program. Parse arguments etc.
  */
 int psftp_main(int argc, char *argv[])
 {
-    int i;
+    int i, ret;
     int portnumber = 0;
     char *userhost, *user;
     int mode = 0;
@@ -2962,7 +2985,7 @@ int psftp_main(int argc, char *argv[])
               " to connect\n");
     }
 
-    do_sftp(mode, modeflags, batchfile);
+    ret = do_sftp(mode, modeflags, batchfile);
 
     if (back != NULL && back->connected(backhandle)) {
        char ch;
@@ -2976,5 +2999,5 @@ int psftp_main(int argc, char *argv[])
     console_provide_logctx(NULL);
     sk_cleanup();
 
-    return 0;
+    return ret;
 }