9fd6981
diff -up openssh-8.7p1/scp.c.scp-sftpdirs openssh-8.7p1/scp.c
9fd6981
--- openssh-8.7p1/scp.c.scp-sftpdirs	2022-02-07 12:31:07.407740407 +0100
9fd6981
+++ openssh-8.7p1/scp.c	2022-02-07 12:31:07.409740424 +0100
9fd6981
@@ -1324,7 +1324,7 @@ source_sftp(int argc, char *src, char *t
9fd6981
 
9fd6981
 	if (src_is_dir && iamrecursive) {
9fd6981
 		if (upload_dir(conn, src, abs_dst, pflag,
9fd6981
-		    SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) {
9fd6981
+		    SFTP_PROGRESS_ONLY, 0, 0, 1, 1) != 0) {
03150f6
			error("failed to upload directory %s to %s", src, targ);
03150f6
			errs = 1;
03150f6
		}
9fd6981
diff -up openssh-8.7p1/sftp-client.c.scp-sftpdirs openssh-8.7p1/sftp-client.c
9fd6981
--- openssh-8.7p1/sftp-client.c.scp-sftpdirs	2021-08-20 06:03:49.000000000 +0200
9fd6981
+++ openssh-8.7p1/sftp-client.c	2022-02-07 12:47:59.117516131 +0100
9fd6981
@@ -971,7 +971,7 @@ do_fsetstat(struct sftp_conn *conn, cons
9fd6981
 
9fd6981
 /* Implements both the realpath and expand-path operations */
9fd6981
 static char *
9fd6981
-do_realpath_expand(struct sftp_conn *conn, const char *path, int expand)
9fd6981
+do_realpath_expand(struct sftp_conn *conn, const char *path, int expand, int create_dir)
9fd6981
 {
9fd6981
 	struct sshbuf *msg;
9fd6981
 	u_int expected_id, count, id;
03150f6
@@ -1033,11 +1033,43 @@ do_realpath_expand(struct sftp_conn *con
03150f6
 		if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
03150f6
 		    (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
9fd6981
 			fatal_fr(r, "parse status");
03150f6
-		error("%s %s: %s", expand ? "expand" : "realpath",
03150f6
-		    path, *errmsg == '\0' ? fx2txt(status) : errmsg);
03150f6
-		free(errmsg);
9fd6981
-		sshbuf_free(msg);
9fd6981
-		return NULL;
9fd6981
+		if ((status == SSH2_FX_NO_SUCH_FILE) && create_dir)  {
9fd6981
+			memset(&a, '\0', sizeof(a));
9fd6981
+			if ((r = do_mkdir(conn, path, &a, 0)) != 0) {
9fd6981
+				sshbuf_free(msg);
9fd6981
+				return NULL;
9fd6981
+			}
03150f6
+			debug2("Sending SSH2_FXP_REALPATH \"%s\" - create dir", path);
9fd6981
+			send_string_request(conn, id, SSH2_FXP_REALPATH,
9fd6981
+					path, strlen(path));
9fd6981
+
9fd6981
+			get_msg(conn, msg);
9fd6981
+			if ((r = sshbuf_get_u8(msg, &type)) != 0 ||
03150f6
+			    (r = sshbuf_get_u32(msg, &id)) != 0)
9fd6981
+				fatal_fr(r, "parse");
9fd6981
+
9fd6981
+			if (id != expected_id)
9fd6981
+				fatal("ID mismatch (%u != %u)", id, expected_id);
9fd6981
+
9fd6981
+			if (type == SSH2_FXP_STATUS) {
03150f6
+				free(errmsg);
9fd6981
+
03150f6
+				if ((r = sshbuf_get_u32(msg, &status)) != 0 ||
03150f6
+				    (r = sshbuf_get_cstring(msg, &errmsg, NULL)) != 0)
9fd6981
+					fatal_fr(r, "parse status");
03150f6
+				error("%s %s: %s", expand ? "expand" : "realpath",
03150f6
+				    path, *errmsg == '\0' ? fx2txt(status) : errmsg);
03150f6
+				free(errmsg);
9fd6981
+				sshbuf_free(msg);
9fd6981
+				return NULL;
9fd6981
+			}
9fd6981
+		} else {
03150f6
+			error("%s %s: %s", expand ? "expand" : "realpath",
03150f6
+			    path, *errmsg == '\0' ? fx2txt(status) : errmsg);
03150f6
+			free(errmsg);
9fd6981
+			sshbuf_free(msg);
9fd6981
+			return NULL;
9fd6981
+		}
9fd6981
 	} else if (type != SSH2_FXP_NAME)
9fd6981
 		fatal("Expected SSH2_FXP_NAME(%u) packet, got %u",
9fd6981
 		    SSH2_FXP_NAME, type);
9fd6981
@@ -1039,9 +1067,9 @@ do_realpath_expand(struct sftp_conn *con
9fd6981
 }
9fd6981
 
9fd6981
 char *
9fd6981
-do_realpath(struct sftp_conn *conn, const char *path)
9fd6981
+do_realpath(struct sftp_conn *conn, const char *path, int create_dir)
9fd6981
 {
9fd6981
-	return do_realpath_expand(conn, path, 0);
9fd6981
+	return do_realpath_expand(conn, path, 0, create_dir);
9fd6981
 }
9fd6981
 
9fd6981
 int
9fd6981
@@ -1055,9 +1083,9 @@ do_expand_path(struct sftp_conn *conn, c
9fd6981
 {
9fd6981
 	if (!can_expand_path(conn)) {
9fd6981
 		debug3_f("no server support, fallback to realpath");
9fd6981
-		return do_realpath_expand(conn, path, 0);
9fd6981
+		return do_realpath_expand(conn, path, 0, 0);
9fd6981
 	}
9fd6981
-	return do_realpath_expand(conn, path, 1);
9fd6981
+	return do_realpath_expand(conn, path, 1, 0);
9fd6981
 }
9fd6981
 
9fd6981
 int
9fd6981
@@ -1807,7 +1835,7 @@ download_dir(struct sftp_conn *conn, con
9fd6981
 	char *src_canon;
9fd6981
 	int ret;
9fd6981
 
9fd6981
-	if ((src_canon = do_realpath(conn, src)) == NULL) {
9fd6981
+	if ((src_canon = do_realpath(conn, src, 0)) == NULL) {
03150f6
		error("download \"%s\": path canonicalization failed", src);
03150f6
		return -1;
03150f6
	}
9fd6981
@@ -2115,12 +2143,12 @@ upload_dir_internal(struct sftp_conn *co
9fd6981
 int
9fd6981
 upload_dir(struct sftp_conn *conn, const char *src, const char *dst,
9fd6981
     int preserve_flag, int print_flag, int resume, int fsync_flag,
9fd6981
-    int follow_link_flag)
9fd6981
+    int follow_link_flag, int create_dir)
9fd6981
 {
9fd6981
 	char *dst_canon;
9fd6981
 	int ret;
9fd6981
 
9fd6981
-	if ((dst_canon = do_realpath(conn, dst)) == NULL) {
9fd6981
+	if ((dst_canon = do_realpath(conn, dst, create_dir)) == NULL) {
03150f6
		error("upload \"%s\": path canonicalization failed", dst);
03150f6
		return -1;
03150f6
	}
9fd6981
@@ -2557,7 +2585,7 @@ crossload_dir(struct sftp_conn *from, st
9fd6981
 	char *from_path_canon;
9fd6981
 	int ret;
9fd6981
 
9fd6981
-	if ((from_path_canon = do_realpath(from, from_path)) == NULL) {
9fd6981
+	if ((from_path_canon = do_realpath(from, from_path, 0)) == NULL) {
03150f6
		error("crossload \"%s\": path canonicalization failed",
03150f6
		    from_path);
03150f6
		return -1;
9fd6981
diff -up openssh-8.7p1/sftp-client.h.scp-sftpdirs openssh-8.7p1/sftp-client.h
9fd6981
--- openssh-8.7p1/sftp-client.h.scp-sftpdirs	2021-08-20 06:03:49.000000000 +0200
9fd6981
+++ openssh-8.7p1/sftp-client.h	2022-02-07 12:31:07.410740433 +0100
9fd6981
@@ -111,7 +111,7 @@ int do_fsetstat(struct sftp_conn *, cons
9fd6981
 int do_lsetstat(struct sftp_conn *conn, const char *path, Attrib *a);
9fd6981
 
9fd6981
 /* Canonicalise 'path' - caller must free result */
9fd6981
-char *do_realpath(struct sftp_conn *, const char *);
9fd6981
+char *do_realpath(struct sftp_conn *, const char *, int);
9fd6981
 
9fd6981
 /* Canonicalisation with tilde expansion (requires server extension) */
9fd6981
 char *do_expand_path(struct sftp_conn *, const char *);
9fd6981
@@ -159,7 +159,7 @@ int do_upload(struct sftp_conn *, const
9fd6981
  * times if 'pflag' is set
9fd6981
  */
9fd6981
 int upload_dir(struct sftp_conn *, const char *, const char *, int, int, int,
9fd6981
-    int, int);
9fd6981
+    int, int, int);
9fd6981
 
9fd6981
 /*
9fd6981
  * Download a 'from_path' from the 'from' connection and upload it to
9fd6981
diff -up openssh-8.7p1/sftp.c.scp-sftpdirs openssh-8.7p1/sftp.c
9fd6981
--- openssh-8.7p1/sftp.c.scp-sftpdirs	2021-08-20 06:03:49.000000000 +0200
9fd6981
+++ openssh-8.7p1/sftp.c	2022-02-07 12:31:07.411740442 +0100
9fd6981
@@ -760,7 +760,7 @@ process_put(struct sftp_conn *conn, cons
9fd6981
 		if (globpath_is_dir(g.gl_pathv[i]) && (rflag || global_rflag)) {
9fd6981
 			if (upload_dir(conn, g.gl_pathv[i], abs_dst,
9fd6981
 			    pflag || global_pflag, 1, resume,
9fd6981
-			    fflag || global_fflag, 0) == -1)
9fd6981
+			    fflag || global_fflag, 0, 0) == -1)
9fd6981
 				err = -1;
9fd6981
 		} else {
9fd6981
 			if (do_upload(conn, g.gl_pathv[i], abs_dst,
9fd6981
@@ -1577,7 +1577,7 @@ parse_dispatch_command(struct sftp_conn
9fd6981
 		if (path1 == NULL || *path1 == '\0')
9fd6981
 			path1 = xstrdup(startdir);
9fd6981
 		path1 = make_absolute(path1, *pwd);
9fd6981
-		if ((tmp = do_realpath(conn, path1)) == NULL) {
9fd6981
+		if ((tmp = do_realpath(conn, path1, 0)) == NULL) {
9fd6981
 			err = 1;
9fd6981
 			break;
9fd6981
 		}
9fd6981
@@ -2160,7 +2160,7 @@ interactive_loop(struct sftp_conn *conn,
9fd6981
 	}
9fd6981
 #endif /* USE_LIBEDIT */
9fd6981
 
9fd6981
-	remote_path = do_realpath(conn, ".");
9fd6981
+	remote_path = do_realpath(conn, ".", 0);
9fd6981
 	if (remote_path == NULL)
9fd6981
 		fatal("Need cwd");
9fd6981
 	startdir = xstrdup(remote_path);