Mercurial > hg > octave-kai > gnulib-hg
changeset 17161:a111021312db
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 "/".
author | Eli Zaretskii <eliz@gnu.org> |
---|---|
date | Tue, 20 Nov 2012 13:47:22 -0800 |
parents | 72f4bab621be |
children | f54c37d872ca |
files | ChangeLog lib/canonicalize-lgpl.c lib/canonicalize.c |
diffstat | 3 files changed, 107 insertions(+), 43 deletions(-) [+] |
line wrap: on
line diff
--- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,20 @@ +2012-11-20 Eli Zaretskii <eliz@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 <ldv@altlinux.org> fts: introduce FTS_VERBATIM
--- 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 @@ 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 @@ 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 @@ } 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 @@ 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 @@ 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 @@ if (resolved) { __set_errno (ENAMETOOLONG); - if (dest > rpath + 1) + if (dest > rpath + prefix_len + 1) dest--; *dest = '\0'; goto error; @@ -299,24 +312,32 @@ 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 @@ } } } - 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';
--- 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 @@ 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 @@ 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 @@ { 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 @@ 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 @@ 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 @@ 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 @@ } } } - 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)