You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
167 lines
4.9 KiB
167 lines
4.9 KiB
diff -up openssh-8.7p1/scp.c.sftpdirs openssh-8.7p1/scp.c |
|
--- openssh-8.7p1/scp.c.sftpdirs 2022-02-02 14:11:12.553447509 +0100 |
|
+++ openssh-8.7p1/scp.c 2022-02-02 14:12:56.081316414 +0100 |
|
@@ -130,6 +130,7 @@ |
|
#include "misc.h" |
|
#include "progressmeter.h" |
|
#include "utf8.h" |
|
+#include "sftp.h" |
|
|
|
#include "sftp-common.h" |
|
#include "sftp-client.h" |
|
@@ -660,7 +661,7 @@ main(int argc, char **argv) |
|
* Finally check the exit status of the ssh process, if one was forked |
|
* and no error has occurred yet |
|
*/ |
|
- if (do_cmd_pid != -1 && errs == 0) { |
|
+ if (do_cmd_pid != -1 && (mode == MODE_SFTP || errs == 0)) { |
|
if (remin != -1) |
|
(void) close(remin); |
|
if (remout != -1) |
|
@@ -1264,13 +1265,18 @@ tolocal(int argc, char **argv, enum scp_ |
|
static char * |
|
prepare_remote_path(struct sftp_conn *conn, const char *path) |
|
{ |
|
+ size_t nslash; |
|
+ |
|
/* Handle ~ prefixed paths */ |
|
- if (*path != '~') |
|
- return xstrdup(path); |
|
if (*path == '\0' || strcmp(path, "~") == 0) |
|
return xstrdup("."); |
|
- if (strncmp(path, "~/", 2) == 0) |
|
- return xstrdup(path + 2); |
|
+ if (*path != '~') |
|
+ return xstrdup(path); |
|
+ if (strncmp(path, "~/", 2) == 0) { |
|
+ if ((nslash = strspn(path + 2, "/")) == strlen(path + 2)) |
|
+ return xstrdup("."); |
|
+ return xstrdup(path + 2 + nslash); |
|
+ } |
|
if (can_expand_path(conn)) |
|
return do_expand_path(conn, path); |
|
/* No protocol extension */ |
|
@@ -1282,10 +1288,16 @@ void |
|
source_sftp(int argc, char *src, char *targ, struct sftp_conn *conn) |
|
{ |
|
char *target = NULL, *filename = NULL, *abs_dst = NULL; |
|
- int target_is_dir; |
|
- |
|
+ int src_is_dir, target_is_dir; |
|
+ Attrib a; |
|
+ struct stat st; |
|
+ |
|
+ memset(&a, '\0', sizeof(a)); |
|
+ if (stat(src, &st) != 0) |
|
+ fatal("stat local \"%s\": %s", src, strerror(errno)); |
|
+ src_is_dir = S_ISDIR(st.st_mode); |
|
if ((filename = basename(src)) == NULL) |
|
- fatal("basename %s: %s", src, strerror(errno)); |
|
+ fatal("basename \"%s\": %s", src, strerror(errno)); |
|
|
|
/* |
|
* No need to glob here - the local shell already took care of |
|
@@ -1295,8 +1307,12 @@ source_sftp(int argc, char *src, char *t |
|
cleanup_exit(255); |
|
target_is_dir = remote_is_dir(conn, target); |
|
if (targetshouldbedirectory && !target_is_dir) { |
|
- fatal("Target is not a directory, but more files selected " |
|
- "for upload"); |
|
+ debug("target directory \"%s\" does not exist", target); |
|
+ a.flags = SSH2_FILEXFER_ATTR_PERMISSIONS; |
|
+ a.perm = st.st_mode | 0700; /* ensure writable */ |
|
+ if (do_mkdir(conn, target, &a, 1) != 0) |
|
+ cleanup_exit(255); /* error already logged */ |
|
+ target_is_dir = 1; |
|
} |
|
if (target_is_dir) |
|
abs_dst = path_append(target, filename); |
|
@@ -1306,14 +1322,17 @@ source_sftp(int argc, char *src, char *t |
|
} |
|
debug3_f("copying local %s to remote %s", src, abs_dst); |
|
|
|
- if (local_is_dir(src) && iamrecursive) { |
|
+ if (src_is_dir && iamrecursive) { |
|
if (upload_dir(conn, src, abs_dst, pflag, |
|
SFTP_PROGRESS_ONLY, 0, 0, 1) != 0) { |
|
- fatal("failed to upload directory %s to %s", |
|
+ error("failed to upload directory %s to %s", |
|
src, abs_dst); |
|
+ errs = 1; |
|
} |
|
- } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) |
|
- fatal("failed to upload file %s to %s", src, abs_dst); |
|
+ } else if (do_upload(conn, src, abs_dst, pflag, 0, 0) != 0) { |
|
+ error("failed to upload file %s to %s", src, abs_dst); |
|
+ errs = 1; |
|
+ } |
|
|
|
free(abs_dst); |
|
free(target); |
|
@@ -1487,14 +1506,15 @@ sink_sftp(int argc, char *dst, const cha |
|
char *abs_dst = NULL; |
|
glob_t g; |
|
char *filename, *tmp = NULL; |
|
- int i, r, err = 0; |
|
+ int i, r, err = 0, dst_is_dir; |
|
+ struct stat st; |
|
|
|
memset(&g, 0, sizeof(g)); |
|
+ |
|
/* |
|
* Here, we need remote glob as SFTP can not depend on remote shell |
|
* expansions |
|
*/ |
|
- |
|
if ((abs_src = prepare_remote_path(conn, src)) == NULL) { |
|
err = -1; |
|
goto out; |
|
@@ -1510,11 +1530,24 @@ sink_sftp(int argc, char *dst, const cha |
|
goto out; |
|
} |
|
|
|
- if (g.gl_matchc > 1 && !local_is_dir(dst)) { |
|
- error("Multiple files match pattern, but destination " |
|
- "\"%s\" is not a directory", dst); |
|
- err = -1; |
|
- goto out; |
|
+ if ((r = stat(dst, &st)) != 0) |
|
+ debug2_f("stat local \"%s\": %s", dst, strerror(errno)); |
|
+ dst_is_dir = r == 0 && S_ISDIR(st.st_mode); |
|
+ |
|
+ if (g.gl_matchc > 1 && !dst_is_dir) { |
|
+ if (r == 0) { |
|
+ error("Multiple files match pattern, but destination " |
|
+ "\"%s\" is not a directory", dst); |
|
+ err = -1; |
|
+ goto out; |
|
+ } |
|
+ debug2_f("creating destination \"%s\"", dst); |
|
+ if (mkdir(dst, 0777) != 0) { |
|
+ error("local mkdir \"%s\": %s", dst, strerror(errno)); |
|
+ err = -1; |
|
+ goto out; |
|
+ } |
|
+ dst_is_dir = 1; |
|
} |
|
|
|
for (i = 0; g.gl_pathv[i] && !interrupted; i++) { |
|
@@ -1525,7 +1558,7 @@ sink_sftp(int argc, char *dst, const cha |
|
goto out; |
|
} |
|
|
|
- if (local_is_dir(dst)) |
|
+ if (dst_is_dir) |
|
abs_dst = path_append(dst, filename); |
|
else |
|
abs_dst = xstrdup(dst); |
|
@@ -1551,7 +1584,8 @@ out: |
|
free(tmp); |
|
globfree(&g); |
|
if (err == -1) { |
|
- fatal("Failed to download file '%s'", src); |
|
+ error("Failed to download '%s'", src); |
|
+ errs = 1; |
|
} |
|
} |
|
|
|
|