Thanks, I made some trivial changes to the patch to get it to compile and use gnulib style and installed the following into gnulib:
>From 169ed317dc19a14160656868b08f3ba409f1a87f Mon Sep 17 00:00:00 2001 From: Eli Zaretskii <e...@gnu.org> Date: Tue, 20 Nov 2012 13:47:22 -0800 Subject: [PATCH] canonicalize, canonicalize-lgpl: support MS-Windows file names See <http://lists.gnu.org/archive/html/bug-gnulib/2012-11/msg00074.html> for test cases, which it'd be nice to add at some point. * lib/canonicalize.c, lib/canonicalize-lgpl.c: Include dosname.h. * lib/canonicalize.c (canonicalize_filename_mode): * lib/canonicalize-lgpl.c (__realpath): Use FILE_SYSTEM_PREFIX_LEN instead of assuming that the first slash is at the beginning of the file name. Use ISSLASH, instead of a literal '/'. Use IS_ABSOLUTE_FILE_NAME instead of comparing the first character with '/'. Test for DOUBLE_SLASH_IS_DISTINCT_ROOT only if the file name does not begin with a drive letter. * lib/canonicalize.c (SLASHES): New macro. (canonicalize_filename_mode): Use SLASHES instead of a literal "/". --- ChangeLog | 17 +++++++++++++ lib/canonicalize-lgpl.c | 65 ++++++++++++++++++++++++++++++---------------- lib/canonicalize.c | 68 ++++++++++++++++++++++++++++++++++--------------- 3 files changed, 107 insertions(+), 43 deletions(-) diff --git a/ChangeLog b/ChangeLog index 348e0d5..9c2555e 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2012-11-20 Eli Zaretskii <e...@gnu.org> + + canonicalize, canonicalize-lgpl: support MS-Windows file names + See <http://lists.gnu.org/archive/html/bug-gnulib/2012-11/msg00074.html> + for test cases, which it'd be nice to add at some point. + * lib/canonicalize.c, lib/canonicalize-lgpl.c: Include dosname.h. + * lib/canonicalize.c (canonicalize_filename_mode): + * lib/canonicalize-lgpl.c (__realpath): + Use FILE_SYSTEM_PREFIX_LEN instead of assuming that the first + slash is at the beginning of the file name. Use ISSLASH, instead + of a literal '/'. Use IS_ABSOLUTE_FILE_NAME instead of comparing + the first character with '/'. Test for + DOUBLE_SLASH_IS_DISTINCT_ROOT only if the file name does not begin + with a drive letter. + * lib/canonicalize.c (SLASHES): New macro. + (canonicalize_filename_mode): Use SLASHES instead of a literal "/". + 2012-11-17 Dmitry V. Levin <l...@altlinux.org> fts: introduce FTS_VERBATIM diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c index 7aa2d92..0888501 100644 --- a/lib/canonicalize-lgpl.c +++ b/lib/canonicalize-lgpl.c @@ -51,6 +51,7 @@ # define __realpath realpath # include "pathmax.h" # include "malloca.h" +# include "dosname.h" # if HAVE_GETCWD # if IN_RELOCWRAPPER /* When building the relocatable program wrapper, use the system's getcwd @@ -101,6 +102,7 @@ __realpath (const char *name, char *resolved) const char *start, *end, *rpath_limit; long int path_max; int num_links = 0; + size_t prefix_len; if (name == NULL) { @@ -143,7 +145,11 @@ __realpath (const char *name, char *resolved) rpath = resolved; rpath_limit = rpath + path_max; - if (name[0] != '/') + /* This is always zero for Posix hosts, but can be 2 for MS-Windows + and MS-DOS X:/foo/bar file names. */ + prefix_len = FILE_SYSTEM_PREFIX_LEN (name); + + if (!IS_ABSOLUTE_FILE_NAME (name)) { if (!__getcwd (rpath, path_max)) { @@ -154,17 +160,22 @@ __realpath (const char *name, char *resolved) } else { - rpath[0] = '/'; - dest = rpath + 1; + dest = rpath; + if (prefix_len) + { + memcpy (rpath, name, prefix_len); + dest += prefix_len; + } + *dest++ = '/'; if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { - if (name[1] == '/' && name[2] != '/') + if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len) *dest++ = '/'; *dest = '\0'; } } - for (start = end = name; *start; start = end) + for (start = end = name + prefix_len; *start; start = end) { #ifdef _LIBC struct stat64 st; @@ -174,11 +185,11 @@ __realpath (const char *name, char *resolved) int n; /* Skip sequence of multiple path-separators. */ - while (*start == '/') + while (ISSLASH (*start)) ++start; /* Find end of path component. */ - for (end = start; *end && *end != '/'; ++end) + for (end = start; *end && !ISSLASH (*end); ++end) /* Nothing. */; if (end - start == 0) @@ -188,17 +199,19 @@ __realpath (const char *name, char *resolved) else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 - && *dest == '/' && dest[1] != '/') + if (dest > rpath + prefix_len + 1) + for (--dest; !ISSLASH (dest[-1]); --dest) + continue; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT + && dest == rpath + 1 && !prefix_len + && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; } else { size_t new_size; - if (dest[-1] != '/') + if (!ISSLASH (dest[-1])) *dest++ = '/'; if (dest + (end - start) >= rpath_limit) @@ -209,7 +222,7 @@ __realpath (const char *name, char *resolved) if (resolved) { __set_errno (ENAMETOOLONG); - if (dest > rpath + 1) + if (dest > rpath + prefix_len + 1) dest--; *dest = '\0'; goto error; @@ -299,24 +312,32 @@ __realpath (const char *name, char *resolved) memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); - if (buf[0] == '/') + if (IS_ABSOLUTE_FILE_NAME (buf)) { - dest = rpath + 1; /* It's an absolute symlink */ + size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); + + if (pfxlen) + memcpy (rpath, buf, pfxlen); + dest = rpath + pfxlen; + *dest++ = '/'; /* It's an absolute symlink */ if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { - if (buf[1] == '/' && buf[2] != '/') + if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen) *dest++ = '/'; *dest = '\0'; } + /* Install the new prefix to be in effect hereafter. */ + prefix_len = pfxlen; } else { /* Back up to previous component, ignore if at root already: */ - if (dest > rpath + 1) - while ((--dest)[-1] != '/'); + if (dest > rpath + prefix_len + 1) + for (--dest; !ISSLASH (dest[-1]); --dest) + continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 - && *dest == '/' && dest[1] != '/') + && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) dest++; } } @@ -327,10 +348,10 @@ __realpath (const char *name, char *resolved) } } } - if (dest > rpath + 1 && dest[-1] == '/') + if (dest > rpath + prefix_len + 1 && ISSLASH (dest[-1])) --dest; - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 - && *dest == '/' && dest[1] != '/') + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && !prefix_len + && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; *dest = '\0'; diff --git a/lib/canonicalize.c b/lib/canonicalize.c index 20ca40b..33ad29f 100644 --- a/lib/canonicalize.c +++ b/lib/canonicalize.c @@ -30,6 +30,7 @@ #include "pathmax.h" #include "xalloc.h" #include "xgetcwd.h" +#include "dosname.h" #define MULTIPLE_BITS_SET(i) (((i) & ((i) - 1)) != 0) @@ -43,6 +44,12 @@ # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 #endif +#if ISSLASH ('\\') +# define SLASHES "/\\" +#else +# define SLASHES "/" +#endif + #if !((HAVE_CANONICALIZE_FILE_NAME && FUNC_REALPATH_WORKS) \ || GNULIB_CANONICALIZE_LGPL) /* Return the canonical absolute name of file NAME. A canonical name @@ -100,6 +107,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) int saved_errno; int can_flags = can_mode & ~CAN_MODE_MASK; bool logical = can_flags & CAN_NOLINKS; + size_t prefix_len; can_mode &= CAN_MODE_MASK; @@ -121,7 +129,11 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) return NULL; } - if (name[0] != '/') + /* This is always zero for Posix hosts, but can be 2 for MS-Windows + and MS-DOS X:/foo/bar file names. */ + prefix_len = FILE_SYSTEM_PREFIX_LEN (name); + + if (!IS_ABSOLUTE_FILE_NAME (name)) { rname = xgetcwd (); if (!rname) @@ -143,24 +155,29 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) { rname = xmalloc (PATH_MAX); rname_limit = rname + PATH_MAX; - rname[0] = '/'; - dest = rname + 1; + dest = rname; + if (prefix_len) + { + memcpy (rname, name, prefix_len); + dest += prefix_len; + } + *dest++ = '/'; if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { - if (name[1] == '/' && name[2] != '/') + if (ISSLASH (name[1]) && !ISSLASH (name[2]) && !prefix_len) *dest++ = '/'; *dest = '\0'; } } - for (start = name; *start; start = end) + for (start = name + prefix_len; *start; start = end) { /* Skip sequence of multiple file name separators. */ - while (*start == '/') + while (ISSLASH (*start)) ++start; /* Find end of component. */ - for (end = start; *end && *end != '/'; ++end) + for (end = start; *end && !ISSLASH (*end); ++end) /* Nothing. */; if (end - start == 0) @@ -170,17 +187,18 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) else if (end - start == 2 && start[0] == '.' && start[1] == '.') { /* Back up to previous component, ignore if at root already. */ - if (dest > rname + 1) - while ((--dest)[-1] != '/'); + if (dest > rname + prefix_len + 1) + for (--dest; !ISSLASH (dest[-1]); --dest) + continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 - && *dest == '/' && dest[1] != '/') + && !prefix_len && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; } else { struct stat st; - if (dest[-1] != '/') + if (!ISSLASH (dest[-1])) *dest++ = '/'; if (dest + (end - start) >= rname_limit) @@ -216,7 +234,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) goto error; if (can_mode == CAN_ALL_BUT_LAST) { - if (end[strspn (end, "/")] || saved_errno != ENOENT) + if (end[strspn (end, SLASHES)] || saved_errno != ENOENT) goto error; continue; } @@ -268,24 +286,32 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) memmove (&extra_buf[n], end, len + 1); name = end = memcpy (extra_buf, buf, n); - if (buf[0] == '/') + if (IS_ABSOLUTE_FILE_NAME (buf)) { - dest = rname + 1; /* It's an absolute symlink */ + size_t pfxlen = FILE_SYSTEM_PREFIX_LEN (buf); + + if (pfxlen) + memcpy (rname, buf, pfxlen); + dest = rname + pfxlen; + *dest++ = '/'; /* It's an absolute symlink */ if (DOUBLE_SLASH_IS_DISTINCT_ROOT) { - if (buf[1] == '/' && buf[2] != '/') + if (ISSLASH (buf[1]) && !ISSLASH (buf[2]) && !pfxlen) *dest++ = '/'; *dest = '\0'; } + /* Install the new prefix to be in effect hereafter. */ + prefix_len = pfxlen; } else { /* Back up to previous component, ignore if at root already: */ - if (dest > rname + 1) - while ((--dest)[-1] != '/'); + if (dest > rname + prefix_len + 1) + for (--dest; !ISSLASH (dest[-1]); --dest) + continue; if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 - && *dest == '/' && dest[1] != '/') + && ISSLASH (*dest) && !ISSLASH (dest[1]) && !prefix_len) dest++; } @@ -301,10 +327,10 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) } } } - if (dest > rname + 1 && dest[-1] == '/') + if (dest > rname + prefix_len + 1 && ISSLASH (dest[-1])) --dest; - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 - && *dest == '/' && dest[1] != '/') + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && !prefix_len + && ISSLASH (*dest) && !ISSLASH (dest[1])) dest++; *dest = '\0'; if (rname_limit != dest + 1) -- 1.7.11.7