David Rothenberger
2008-Nov-15  21:15 UTC
[PATCH] Don't strip two leading slashes from paths.
rsync 3.0.4 will transform a path like '//machine/share/dir' to 
'/machine/share/dir' when the --protect flag is provided. This causes a 
problem with Cygwin, where the two leading slashes are meaningful 
(access of a remote Windows share).
[[[
% rsync -s localhost://tela/downloads
rsync: link_stat "/tela/downloads" failed: No such file or directory
(2)
rsync error: some files/attrs were not transferred (see previous errors) 
(code 23) at 
/home/lapo/packaging/rsync-3.0.4-1/src/rsync-3.0.4/main.c(1506) 
[receiver=3.0.4]
]]]
http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_11
mentions that "[a] pathname that begins with two successive slashes may 
be interpreted in an implementation-defined manner, although more than 
two leading slashes shall be treated as a single slash."
The attached patch prevents two leading slashes from being converted to 
one and works fine for me with Cygwin:
[[[
% rsync -s localhost://tela/downloads
drwxr-xr-x           0 2008/01/14 09:46:23 downloads
]]]
Unfortunately, it doesn't fully conform to the POSIX specification 
because it also translates '///' to '//' instead of '/'
as required.
Does this patch (or a modified version that conforms to POSIX) stand a 
chance of being accepted? Should I create a bugzilla issue and attach it 
there? Should I work on modifying the patch to conform to POSIX?
-- 
David Rothenberger  ----  daveroth@acm.org
-------------- next part --------------
Index: util.c
==================================================================---
util.c.orig
+++ util.c
@@ -821,8 +821,12 @@ unsigned int clean_fname(char *name, int
 	if (!name)
 		return 0;
 
-	if ((anchored = *f == '/') != 0)
+	if ((anchored = *f == '/') != 0) {
 		*t++ = *f++;
+ 		/* keep "//" */
+                 if (*f == '/')
+ 			*t++ = *f++;
+	}
 	else if (flags & CFN_KEEP_DOT_DIRS && *f == '.' &&
f[1] == '/') {
 		*t++ = *f++;
 		*t++ = *f++;
On Sat, Nov 15, 2008 at 01:09:20PM -0800, David Rothenberger wrote:> Unfortunately, it doesn't fully conform to the POSIX specification because > it also translates '///' to '//' instead of '/' as required.An easy fix for that is to change your newly added "if" to this: if (*f == '/' && f[1] != '/') The one thing I wonder about with this is if "//" (with nothing else) should be interpreted as "//" or "/"? If it should collapse to "/", we could use this: if (*f == '/' && f[1] != '/' && f[1] != '\0') Is there a need to use "//" for something special? I'm thinking I'll go ahead an preserve it, just in case. Thanks for your patch! ..wayne..
On Sat, Nov 15, 2008 at 01:09:20PM -0800, David Rothenberger wrote:> Does this patch (or a modified version that conforms to POSIX) stand a > chance of being accepted?There's a problem with including this in the mainstream version: if we don't turn //some/path into /some/path, it won't match a daemon-config exclusion of "/some/path". So, this would need to be conditionally compiled into the code so that it only affects systems that treat a leading "//" as a different path from a leading "/". ..wayne..