> I don't see the ambuguity here, the thing that will be transferred here > will always be the contents of whatever directory ../../foo resolves to > as sftp doesn't transfer symlinks (though maybe one day we'll get around > to implementing https://bugzilla.mindrot.org/show_bug.cgi?id=428) My personal thinking is that in every other scenario than with . and .. the directory is uploaded along with the contents... not just the contents. In FreeBSD, at least, . and .. are not symbolic links, so I wouldn't expect them to be treated as symbolic links either. In my opinion, .and .. are special cases in how they need to be handled and when thinking about how to do so, we should think about what would happen in every other scenario, which is that the directory goes along with its contents. After all, one could just glob everything if they only wanted the contents. I'm not especially experienced with Unix programming so perhaps there's a better implementation out there, but here's what I propose: diff --git a/sftp.c b/sftp.c index bdedd1416..042c1f358 100644 --- a/sftp.c +++ b/sftp.c @@ -735,6 +735,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, const char *pwd, int pflag, int rflag, int resume, int fflag) { char *tmp_dst = NULL; + char *abs_src = NULL; char *abs_dst = NULL; char *tmp = NULL, *filename = NULL; glob_t g; @@ -782,6 +783,18 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, goto out; } + if (strcmp(filename, ".") == 0) + { + abs_src = getcwd(NULL, MAXPATHLEN); + filename = basename(abs_src); + } + if (strcmp(filename, "..") == 0) + { + abs_src = getcwd(NULL, MAXPATHLEN); + filename = dirname(abs_src); + filename = basename(filename); + } + free(abs_dst); abs_dst = NULL; if (g.gl_matchc == 1 && tmp_dst) { @@ -820,6 +833,7 @@ process_put(struct sftp_conn *conn, const char *src, const char *dst, } out: + free(abs_src); free(abs_dst); free(tmp_dst); globfree(&g); Best, Andrew ________________________________ From: Damien Miller <djm@xxxxxxxxxxx> Sent: Friday, July 4, 2025 3:02 AM To: Philipp Marek <philipp@xxxxxxxxxxxxx> Cc: openssh-unix-dev@xxxxxxxxxxx <openssh-unix-dev@xxxxxxxxxxx>; Andrew Wood <andrew1tree@xxxxxxxxx> Subject: Re: SFTP's handling of "." and ".." On Fri, 4 Jul 2025, Philipp Marek via openssh-unix-dev wrote: > Is this enough? I think so? > What about > > put -r ../ dest > put -r ../. dest > put -r ../.. dest The "filename" variable I check in my patch comes from basename(3), so it should be the final path component only. AFAIK basename("../") yields "..", so the 2nd case should be ok too. > I guess this resolves to the question whether source path structures > should be built in the destination (like -R for rsync says) or not. > > put -r ../../foo/.. dest > > With foo being a symlink the intention might not be clear (which > containing directory, of the symlink or its target?) I don't see the ambuguity here, the thing that will be transferred here will always be the contents of whatever directory ../../foo resolves to as sftp doesn't transfer symlinks (though maybe one day we'll get around to implementing https://bugzilla.mindrot.org/show_bug.cgi?id=428) -d _______________________________________________ openssh-unix-dev mailing list openssh-unix-dev@xxxxxxxxxxx https://lists.mindrot.org/mailman/listinfo/openssh-unix-dev