From: Eric Blake Date: Thu, 10 Sep 2009 23:21:09 +0000 (-0600) Subject: canonicalize, canonicalize-lgpl: honor // if distinct from / X-Git-Tag: v0.1~5468 X-Git-Url: http://erislabs.org.uk/gitweb/?a=commitdiff_plain;h=35bd2ff772f9bc95f8e9d8e2a9bb5fc09331ed9c;p=gnulib.git canonicalize, canonicalize-lgpl: honor // if distinct from / * modules/canonicalize (Files): Add double-slash-root.m4. * modules/canonicalize-lgpl (Files): Likewise. * m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE) (gl_CANONICALIZE_LGPL_SEPARATE): Add dependency. * lib/canonicalize.c (DOUBLE_SLASH_IS_DISTINCT_ROOT): Provide fallback definition. (canonicalize_filename_mode): Use it to protect //. * lib/canonicalize-lgpl.c (DOUBLE_SLASH_IS_DISTINCT_ROOT) (__realpath): Likewise. * tests/test-canonicalize.c (main): Test this. * tests/test-canonicalize-lgpl.c (main): Likewise. * modules/canonicalize-tests (Depends-on): Add same-inode. * modules/canonicalize-lgpl-tests (Depends-on): Likewise. Signed-off-by: Eric Blake --- diff --git a/ChangeLog b/ChangeLog index 6121def98..b0464b4ae 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,20 @@ 2009-09-17 Eric Blake + canonicalize, canonicalize-lgpl: honor // if distinct from / + * modules/canonicalize (Files): Add double-slash-root.m4. + * modules/canonicalize-lgpl (Files): Likewise. + * m4/canonicalize.m4 (gl_FUNC_CANONICALIZE_FILENAME_MODE) + (gl_CANONICALIZE_LGPL_SEPARATE): Add dependency. + * lib/canonicalize.c (DOUBLE_SLASH_IS_DISTINCT_ROOT): Provide + fallback definition. + (canonicalize_filename_mode): Use it to protect //. + * lib/canonicalize-lgpl.c (DOUBLE_SLASH_IS_DISTINCT_ROOT) + (__realpath): Likewise. + * tests/test-canonicalize.c (main): Test this. + * tests/test-canonicalize-lgpl.c (main): Likewise. + * modules/canonicalize-tests (Depends-on): Add same-inode. + * modules/canonicalize-lgpl-tests (Depends-on): Likewise. + canonicalize-lgpl: fix glibc bug with trailing slash * m4/canonicalize-lgpl.m4: Move contents... * m4/canonicalize.m4: ...here. diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c index fbde01bbc..fa310fb59 100644 --- a/lib/canonicalize-lgpl.c +++ b/lib/canonicalize-lgpl.c @@ -67,6 +67,10 @@ # endif #endif +#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +#endif + #if !FUNC_REALPATH_WORKS || defined _LIBC /* Return the canonical absolute name of file NAME. A canonical name does not contain any `.', `..' components nor any repeated path @@ -141,6 +145,8 @@ __realpath (const char *name, char *resolved) { rpath[0] = '/'; dest = rpath + 1; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && name[1] == '/') + *dest++ = '/'; } for (start = end = name; *start; start = end) @@ -169,6 +175,9 @@ __realpath (const char *name, char *resolved) /* 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++; } else { @@ -276,11 +285,21 @@ __realpath (const char *name, char *resolved) name = end = memcpy (extra_buf, buf, n); if (buf[0] == '/') - dest = rpath + 1; /* It's an absolute symlink */ + { + dest = rpath + 1; /* It's an absolute symlink */ + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/') + *dest++ = '/'; + } else - /* Back up to previous component, ignore if at root already: */ - if (dest > rpath + 1) - while ((--dest)[-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++; + } } else if (!S_ISDIR (st.st_mode) && *end != '\0') { @@ -291,6 +310,8 @@ __realpath (const char *name, char *resolved) } if (dest > rpath + 1 && dest[-1] == '/') --dest; + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rpath + 1 && *dest == '/') + dest++; *dest = '\0'; if (extra_buf) diff --git a/lib/canonicalize.c b/lib/canonicalize.c index 3a0154bd0..9434699fd 100644 --- a/lib/canonicalize.c +++ b/lib/canonicalize.c @@ -31,6 +31,10 @@ #include "xalloc.h" #include "xgetcwd.h" +#ifndef DOUBLE_SLASH_IS_DISTINCT_ROOT +# define DOUBLE_SLASH_IS_DISTINCT_ROOT 0 +#endif + #if !((HAVE_CANONICALIZE_FILE_NAME && FUNC_REALPATH_WORKS) \ || GNULIB_CANONICALIZE_LGPL) /* Return the canonical absolute name of file NAME. A canonical name @@ -122,6 +126,8 @@ 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++ = '/'; } for (start = name; *start; start = end) @@ -143,6 +149,9 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) /* Back up to previous component, ignore if at root already. */ if (dest > rname + 1) while ((--dest)[-1] != '/'); + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 + && *dest == '/') + dest++; } else { @@ -226,11 +235,21 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode) name = end = memcpy (extra_buf, buf, n); if (buf[0] == '/') - dest = rname + 1; /* It's an absolute symlink */ + { + dest = rname + 1; /* It's an absolute symlink */ + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && buf[1] == '/') + *dest++ = '/'; + } else - /* Back up to previous component, ignore if at root already: */ - if (dest > rname + 1) - while ((--dest)[-1] != '/'); + { + /* Back up to previous component, ignore if at root + already: */ + if (dest > rname + 1) + while ((--dest)[-1] != '/'); + if (DOUBLE_SLASH_IS_DISTINCT_ROOT && dest == rname + 1 + && *dest == '/') + dest++; + } free (buf); } @@ -246,6 +265,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 == '/') + dest++; *dest = '\0'; free (extra_buf); diff --git a/m4/canonicalize.m4 b/m4/canonicalize.m4 index 47c5c01ad..2d24350e1 100644 --- a/m4/canonicalize.m4 +++ b/m4/canonicalize.m4 @@ -1,4 +1,4 @@ -# canonicalize.m4 serial 15 +# canonicalize.m4 serial 16 dnl Copyright (C) 2003-2007, 2009 Free Software Foundation, Inc. @@ -14,6 +14,7 @@ AC_DEFUN([gl_FUNC_CANONICALIZE_FILENAME_MODE], AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CHECK_FUNCS_ONCE([canonicalize_file_name]) + AC_REQUIRE([gl_DOUBLE_SLASH_ROOT]) AC_REQUIRE([gl_FUNC_REALPATH_WORKS]) if test $ac_cv_func_canonicalize_file_name = no; then HAVE_CANONICALIZE_FILE_NAME=0 @@ -47,6 +48,7 @@ AC_DEFUN([gl_CANONICALIZE_LGPL_SEPARATE], [ AC_REQUIRE([gl_USE_SYSTEM_EXTENSIONS]) AC_CHECK_FUNCS_ONCE([canonicalize_file_name getcwd readlink]) + AC_REQUIRE([gl_DOUBLE_SLASH_ROOT]) AC_REQUIRE([gl_FUNC_REALPATH_WORKS]) AC_CHECK_HEADERS_ONCE([sys/param.h]) ]) diff --git a/modules/canonicalize b/modules/canonicalize index d039854f1..39a5102e3 100644 --- a/modules/canonicalize +++ b/modules/canonicalize @@ -5,6 +5,7 @@ Files: lib/canonicalize.h lib/canonicalize.c m4/canonicalize.m4 +m4/double-slash-root.m4 Depends-on: areadlink-with-size diff --git a/modules/canonicalize-lgpl b/modules/canonicalize-lgpl index f6b005579..6a748f300 100644 --- a/modules/canonicalize-lgpl +++ b/modules/canonicalize-lgpl @@ -4,6 +4,7 @@ realpath, canonical_file_name: Provide canonical absolute file name Files: lib/canonicalize-lgpl.c m4/canonicalize.m4 +m4/double-slash-root.m4 Depends-on: alloca-opt diff --git a/modules/canonicalize-lgpl-tests b/modules/canonicalize-lgpl-tests index 200950986..cf96c58d5 100644 --- a/modules/canonicalize-lgpl-tests +++ b/modules/canonicalize-lgpl-tests @@ -2,6 +2,7 @@ Files: tests/test-canonicalize-lgpl.c Depends-on: +same-inode configure.ac: AC_CHECK_FUNCS_ONCE([symlink]) diff --git a/modules/canonicalize-tests b/modules/canonicalize-tests index f91c5f92e..202d639f5 100644 --- a/modules/canonicalize-tests +++ b/modules/canonicalize-tests @@ -3,6 +3,7 @@ tests/test-canonicalize.c Depends-on: progname +same-inode configure.ac: AC_CHECK_FUNCS_ONCE([symlink]) diff --git a/tests/test-canonicalize-lgpl.c b/tests/test-canonicalize-lgpl.c index f2c4e7a04..39025fa39 100644 --- a/tests/test-canonicalize-lgpl.c +++ b/tests/test-canonicalize-lgpl.c @@ -27,6 +27,8 @@ #include #include +#include "same-inode.h" + #if !HAVE_SYMLINK # define symlink(a,b) (-1) #endif /* !HAVE_SYMLINK */ @@ -115,6 +117,7 @@ main () ASSERT (symlink ("wum", BASE "/ouk") == 0); ASSERT (symlink ("../ise", BASE "/ket") == 0); ASSERT (mkdir (BASE "/lum", 0700) == 0); + ASSERT (symlink ("//.//../..", BASE "/droot") == 0); /* Check that the symbolic link to a file can be resolved. */ { @@ -182,7 +185,33 @@ main () ASSERT (errno == ELOOP); } + /* Check that leading // is honored correctly. */ + { + struct stat st1; + struct stat st2; + char *result1 = canonicalize_file_name ("//."); + char *result2 = canonicalize_file_name (BASE "/droot"); + ASSERT (result1); + ASSERT (result2); + ASSERT (stat ("/", &st1) == 0); + ASSERT (stat ("//", &st2) == 0); + if (SAME_INODE (st1, st2)) + { + ASSERT (strcmp (result1, "/") == 0); + ASSERT (strcmp (result2, "/") == 0); + } + else + { + ASSERT (strcmp (result1, "//") == 0); + ASSERT (strcmp (result2, "//") == 0); + } + free (result1); + free (result2); + } + + /* Cleanup. */ + ASSERT (remove (BASE "/droot") == 0); ASSERT (remove (BASE "/plo") == 0); ASSERT (remove (BASE "/huk") == 0); ASSERT (remove (BASE "/bef") == 0); diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c index 010ca701d..f8dcc54d5 100644 --- a/tests/test-canonicalize.c +++ b/tests/test-canonicalize.c @@ -28,6 +28,8 @@ #include #include +#include "same-inode.h" + #if !HAVE_SYMLINK # define symlink(a,b) (-1) #endif @@ -138,6 +140,7 @@ main () ASSERT (mkdir (BASE "/d", 0700) == 0); ASSERT (close (creat (BASE "/d/2", 0600)) == 0); ASSERT (symlink ("../s/2", BASE "/d/1") == 0); + ASSERT (symlink ("//.//../..", BASE "/droot") == 0); /* Check that the symbolic link to a file can be resolved. */ { @@ -281,7 +284,42 @@ main () free (result2); } + /* Check that leading // is honored correctly. */ + { + struct stat st1; + struct stat st2; + char *result1 = canonicalize_file_name ("//."); + char *result2 = canonicalize_filename_mode ("//.", CAN_EXISTING); + char *result3 = canonicalize_file_name (BASE "/droot"); + char *result4 = canonicalize_filename_mode (BASE "/droot", CAN_EXISTING); + ASSERT (result1); + ASSERT (result2); + ASSERT (result3); + ASSERT (result4); + ASSERT (stat ("/", &st1) == 0); + ASSERT (stat ("//", &st2) == 0); + if (SAME_INODE (st1, st2)) + { + ASSERT (strcmp (result1, "/") == 0); + ASSERT (strcmp (result2, "/") == 0); + ASSERT (strcmp (result3, "/") == 0); + ASSERT (strcmp (result4, "/") == 0); + } + else + { + ASSERT (strcmp (result1, "//") == 0); + ASSERT (strcmp (result2, "//") == 0); + ASSERT (strcmp (result3, "//") == 0); + ASSERT (strcmp (result4, "//") == 0); + } + free (result1); + free (result2); + free (result3); + free (result4); + } + /* Cleanup. */ + ASSERT (remove (BASE "/droot") == 0); ASSERT (remove (BASE "/d/1") == 0); ASSERT (remove (BASE "/d/2") == 0); ASSERT (remove (BASE "/d") == 0);