SFTP's handling of "." and ".."
Andrew Wood
andrew1tree at gmail.com
Sat Jul 5 09:36:13 AEST 2025
> 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 at mindrot.org>
Sent: Friday, July 4, 2025 3:02 AM
To: Philipp Marek <philipp at marek.priv.at>
Cc: openssh-unix-dev at mindrot.org <openssh-unix-dev at mindrot.org>; Andrew Wood <andrew1tree at gmail.com>
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
More information about the openssh-unix-dev
mailing list