Update docs for change to UTF-8 by default, and emphasise UTF-8 more generally.
[sgt/putty] / psftp.c
diff --git a/psftp.c b/psftp.c
index a42b162..ab287df 100644 (file)
--- a/psftp.c
+++ b/psftp.c
@@ -37,6 +37,7 @@ char *pwd, *homedir;
 static Backend *back;
 static void *backhandle;
 static Conf *conf;
+int sent_eof = FALSE;
 
 /* ----------------------------------------------------------------------
  * Higher-level helper functions used in commands.
@@ -212,6 +213,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
     uint64 offset;
     WFile *file;
     int ret, shown_err = FALSE;
+    struct fxp_attrs attrs;
 
     /*
      * In recursive mode, see if we're dealing with a directory.
@@ -219,7 +221,6 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
      * subsequent FXP_OPEN will return a usable error message.)
      */
     if (recurse) {
-       struct fxp_attrs attrs;
        int result;
 
        sftp_register(req = fxp_stat_send(fname));
@@ -383,7 +384,13 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
        }
     }
 
-    sftp_register(req = fxp_open_send(fname, SSH_FXF_READ));
+    sftp_register(req = fxp_stat_send(fname));
+    rreq = sftp_find_request(pktin = sftp_recv());
+    assert(rreq == req);
+    if (!fxp_stat_recv(pktin, rreq, &attrs))
+        attrs.flags = 0;
+
+    sftp_register(req = fxp_open_send(fname, SSH_FXF_READ, NULL));
     rreq = sftp_find_request(pktin = sftp_recv());
     assert(rreq == req);
     fh = fxp_open_recv(pktin, rreq);
@@ -396,7 +403,7 @@ int sftp_get_file(char *fname, char *outfname, int recurse, int restart)
     if (restart) {
        file = open_existing_wfile(outfname, NULL);
     } else {
-       file = open_new_file(outfname);
+       file = open_new_file(outfname, GET_PERMISSIONS(attrs));
     }
 
     if (!file) {
@@ -500,6 +507,8 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
     uint64 offset;
     RFile *file;
     int ret, err, eof;
+    struct fxp_attrs attrs;
+    long permissions;
 
     /*
      * In recursive mode, see if we're dealing with a directory.
@@ -507,7 +516,6 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
      * subsequent fopen will return an error message.)
      */
     if (recurse && file_type(fname) == FILE_TYPE_DIRECTORY) {
-       struct fxp_attrs attrs;
        int result;
        int nnames, namesize;
        char *name, **ournames;
@@ -630,16 +638,19 @@ int sftp_put_file(char *fname, char *outfname, int recurse, int restart)
        return 1;
     }
 
-    file = open_existing_file(fname, NULL, NULL, NULL);
+    file = open_existing_file(fname, NULL, NULL, NULL, &permissions);
     if (!file) {
        printf("local: unable to open %s\n", fname);
        return 0;
     }
+    attrs.flags = 0;
+    PUT_PERMISSIONS(attrs, permissions);
     if (restart) {
-       sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE));
+       sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE, &attrs));
     } else {
        sftp_register(req = fxp_open_send(outfname, SSH_FXF_WRITE |
-                                         SSH_FXF_CREAT | SSH_FXF_TRUNC));
+                                         SSH_FXF_CREAT | SSH_FXF_TRUNC,
+                                          &attrs));
     }
     rreq = sftp_find_request(pktin = sftp_recv());
     assert(rreq == req);
@@ -819,7 +830,17 @@ char *sftp_wildcard_get_filename(SftpWildcardMatcher *swcm)
                    printf("%s: reading directory: %s\n", swcm->prefix,
                           fxp_error());
                return NULL;
-           }
+           } else if (swcm->names->nnames == 0) {
+                /*
+                 * Another failure mode which we treat as EOF is if
+                 * the server reports success from FXP_READDIR but
+                 * returns no actual names. This is unusual, since
+                 * from most servers you'd expect at least "." and
+                 * "..", but there's nothing forbidding a server from
+                 * omitting those if it wants to.
+                 */
+                return NULL;
+            }
 
            swcm->namepos = 0;
        }
@@ -970,6 +991,7 @@ int sftp_cmd_close(struct sftp_command *cmd)
     if (back != NULL && back->connected(backhandle)) {
        char ch;
        back->special(backhandle, TS_EOF);
+        sent_eof = TRUE;
        sftp_recvdata(&ch, 1);
     }
     do_sftp_cleanup();
@@ -2265,10 +2287,13 @@ struct sftp_command *sftp_getcmd(FILE *fp, int mode, int modeflags)
         *      >this has "quotes" in<
         *      >and"this"<
         */
-       while (*p) {
+       while (1) {
            /* skip whitespace */
            while (*p && (*p == ' ' || *p == '\t'))
                p++;
+            /* terminate loop */
+            if (!*p)
+                break;
            /* mark start of word */
            q = r = p;                 /* q sits at start, r writes word */
            quoting = 0;
@@ -2352,6 +2377,7 @@ void do_sftp_cleanup()
     char ch;
     if (back) {
        back->special(backhandle, TS_EOF);
+        sent_eof = TRUE;
        sftp_recvdata(&ch, 1);
        back->free(backhandle);
        sftp_cleanup_request();
@@ -2560,6 +2586,19 @@ int from_backend_untrusted(void *frontend_handle, const char *data, int len)
     assert(!"Unexpected call to from_backend_untrusted()");
     return 0; /* not reached */
 }
+int from_backend_eof(void *frontend)
+{
+    /*
+     * We expect to be the party deciding when to close the
+     * connection, so if we see EOF before we sent it ourselves, we
+     * should panic.
+     */
+    if (!sent_eof) {
+        connection_fatal(frontend,
+                         "Received unexpected end-of-file from SFTP server");
+    }
+    return FALSE;
+}
 int sftp_recvdata(char *buf, int len)
 {
     outptr = (unsigned char *) buf;
@@ -2884,12 +2923,14 @@ int psftp_main(int argc, char *argv[])
            if (flags & FLAG_VERBOSE)
                verbose = 1;
        } else if (strcmp(argv[i], "-h") == 0 ||
-                  strcmp(argv[i], "-?") == 0) {
+                  strcmp(argv[i], "-?") == 0 ||
+                   strcmp(argv[i], "--help") == 0) {
            usage();
         } else if (strcmp(argv[i], "-pgpfp") == 0) {
             pgp_fingerprints();
             return 1;
-       } else if (strcmp(argv[i], "-V") == 0) {
+       } else if (strcmp(argv[i], "-V") == 0 ||
+                   strcmp(argv[i], "--version") == 0) {
            version();
        } else if (strcmp(argv[i], "-batch") == 0) {
            console_batch_mode = 1;
@@ -2942,6 +2983,7 @@ int psftp_main(int argc, char *argv[])
     if (back != NULL && back->connected(backhandle)) {
        char ch;
        back->special(backhandle, TS_EOF);
+        sent_eof = TRUE;
        sftp_recvdata(&ch, 1);
     }
     do_sftp_cleanup();