X-Git-Url: http://erislabs.net/gitweb/?a=blobdiff_plain;f=lib%2Fcanonicalize.c;h=583c1a4af200903b7f6b935191b43cddc28bc889;hb=66f5e6513c46dffcb40b216e3709b84ab5fbc392;hp=18acd061324992ed50f109d4f82f01ba748ec56b;hpb=b2e2010c7c902235b5efb5bd3c6529f61b093aa4;p=gnulib.git diff --git a/lib/canonicalize.c b/lib/canonicalize.c index 18acd0613..583c1a4af 100644 --- a/lib/canonicalize.c +++ b/lib/canonicalize.c @@ -1,5 +1,5 @@ /* Return the canonical absolute name of a given file. - Copyright (C) 1996-2010 Free Software Foundation, Inc. + Copyright (C) 1996-2012 Free Software Foundation, Inc. This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -31,6 +31,14 @@ #include "xalloc.h" #include "xgetcwd.h" +#define MULTIPLE_BITS_SET(i) (((i) & ((i) - 1)) != 0) + +/* In this file, we cannot handle file names longer than PATH_MAX. + On systems with no file name length limit, use a fallback. */ +#ifndef PATH_MAX +# define PATH_MAX 8192 +#endif + #ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT # define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 #endif @@ -38,7 +46,7 @@ #if !((HAVE_CANONICALIZE_FILE_NAME && FUNC_REALPATH_WORKS) \ || GNULIB_CANONICALIZE_LGPL) /* Return the canonical absolute name of file NAME. A canonical name - does not contain any `.', `..' components nor any repeated file name + does not contain any ".", ".." components nor any repeated file name separators ('/') or symlinks. All components must exist. The result is malloc'd. */ @@ -75,9 +83,10 @@ seen_triple (Hash_table **ht, char const *filename, struct stat const *st) /* Return the canonical absolute name of file NAME, while treating missing elements according to CAN_MODE. A canonical name - does not contain any `.', `..' components nor any repeated file name - separators ('/') or symlinks. Whether components must exist - or not depends on canonicalize mode. The result is malloc'd. */ + does not contain any ".", ".." components nor any repeated file name + separators ('/') or, depending on other CAN_MODE flags, symlinks. + Whether components must exist or not depends on canonicalize mode. + The result is malloc'd. */ char * canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) @@ -89,6 +98,16 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) size_t extra_len = 0; Hash_table *ht = NULL; int saved_errno; + int can_flags = can_mode & ~CAN_MODE_MASK; + can_mode &= CAN_MODE_MASK; + bool logical = can_flags & CAN_NOLINKS; + /* Perhaps in future we might support CAN_NOALLOC with CAN_NOLINKS. */ + + if (MULTIPLE_BITS_SET (can_mode)) + { + errno = EINVAL; + return NULL; + } if (name == NULL) { @@ -126,8 +145,12 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) rname_limit = rname + PATH_MAX; rname[0] = '/'; dest = rname + 1; - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/') - *dest++ = '/'; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT) + { + if (name[1] == '/' && name[2] != '/') + *dest++ = '/'; + *dest = '\0'; + } } for (start = name; *start; start = end) @@ -150,7 +173,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) if (dest > rname + 1) while ((--dest)[-1] != '/'); if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 - && *dest == '/') + && *dest == '/' && dest[1] != '/') dest++; } else @@ -179,7 +202,14 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) dest += end - start; *dest = '\0'; - if (lstat (rname, &st) != 0) + if (logical && (can_mode == CAN_MISSING)) + { + /* Avoid the stat in this case as it's inconsequential. + i.e. we're neither resolving symlinks or testing + component existence. */ + st.st_mode = 0; + } + else if ((logical ? stat (rname, &st) : lstat (rname, &st)) != 0) { saved_errno = errno; if (can_mode == CAN_EXISTING) @@ -241,8 +271,12 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) if (buf[0] == '/') { dest = rname + 1; /* It's an absolute symlink */ - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/') - *dest++ = '/'; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT) + { + if (buf[1] == '/' && buf[2] != '/') + *dest++ = '/'; + *dest = '\0'; + } } else { @@ -251,7 +285,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) if (dest > rname + 1) while ((--dest)[-1] != '/'); if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 - && *dest == '/') + && *dest == '/' && dest[1] != '/') dest++; } @@ -269,7 +303,8 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) } if (dest > rname + 1 && dest[-1] == '/') --dest; - if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 && *dest == '/') + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 + && *dest == '/' && dest[1] != '/') dest++; *dest = '\0'; if (rname_limit != dest + 1)