[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/6] realpath: fix problems with root handling
From: |
Eric Blake |
Subject: |
[PATCH 2/6] realpath: fix problems with root handling |
Date: |
Wed, 14 Mar 2012 14:38:13 -0600 |
When --relative-base is /, all other paths should be treated as
relative (except for // where it matters).
Also, on platforms like Cygwin where / and // are distinct, realpath
was incorrectly collapsing // into /. http://debbugs.gnu.org/10472.
* src/realpath.c (path_prefix, path_common_prefix): Treat /
and // as having no common match.
(relpath): Allow for no match even without --relative-base.
* NEWS: Document this.
---
NEWS | 5 +++++
src/realpath.c | 28 ++++++++++++++++++++++++++--
2 files changed, 31 insertions(+), 2 deletions(-)
diff --git a/NEWS b/NEWS
index f783afb..e9b3d20 100644
--- a/NEWS
+++ b/NEWS
@@ -57,6 +57,11 @@ GNU coreutils NEWS -*-
outline -*-
surprising rename no-op behavior). Now, mv handles this case by skipping
the usually-useless rename and simply unlinking A.
+ realpath no longer mishandles a root directory. This was most
+ noticeable on platforms where // is a different directory than /,
+ but could also be observed with --relative-base=/ or
+ --relative-to=/. [bug since the beginning, in 8.15]
+
** Improvements
ls can be much more efficient, especially with large directories on file
diff --git a/src/realpath.c b/src/realpath.c
index 2dc5e11..7834c62 100644
--- a/src/realpath.c
+++ b/src/realpath.c
@@ -108,10 +108,25 @@ realpath_canon (const char *fname, int can_mode)
return can_fname;
}
-/* Test whether prefix is parent or match of path. */
+/* Test whether canonical prefix is parent or match of path. */
static bool _GL_ATTRIBUTE_PURE
path_prefix (const char *prefix, const char *path)
{
+ /* We already know prefix[0] and path[0] are '/'. */
+
+ prefix++;
+ path++;
+
+ /* '/' is the prefix of everything except '//' (since we know '//'
+ is only present after canonicalization if it is distinct). */
+ if (!*prefix)
+ return *path != '/';
+
+ /* Likewise, '//' is a prefix of any double-slash path. */
+ if (*prefix == '/' && !prefix[1])
+ return *path == '/';
+
+ /* All remaining prefix have a non-slash portion. */
while (*prefix && *path)
{
if (*prefix != *path)
@@ -123,7 +138,7 @@ path_prefix (const char *prefix, const char *path)
}
/* Return the length of the longest common prefix
- of PATH1 and PATH2, ensuring only full path components
+ of canonical PATH1 and PATH2, ensuring only full path components
are matched. Return 0 on no match. */
static int _GL_ATTRIBUTE_PURE
path_common_prefix (const char *path1, const char *path2)
@@ -131,6 +146,12 @@ path_common_prefix (const char *path1, const char *path2)
int i = 0;
int ret = 0;
+ /* We already know path1[0] and path2[0] are '/'. Special case
+ '//', which is only present in a canonical name on platforms
+ where it is distinct. */
+ if ((path1[1] == '/') != (path2[1] == '/'))
+ return 0;
+
while (*path1 && *path2)
{
if (*path1 != *path2)
@@ -168,6 +189,9 @@ relpath (const char *can_fname)
/* Skip the prefix common to --relative-to and path. */
int common_index = path_common_prefix (can_relative_to, can_fname);
+ if (!common_index)
+ return false;
+
const char *relto_suffix = can_relative_to + common_index;
const char *fname_suffix = can_fname + common_index;
--
1.7.7.6
- [PATCH 0/6] realpath cleanups, Eric Blake, 2012/03/14
- [PATCH 5/6] doc: clarify current realpath --relative-base behavior, Eric Blake, 2012/03/14
- [PATCH 2/6] realpath: fix problems with root handling,
Eric Blake <=
- [PATCH 6/6] realpath: let --relative-base work even as child of --relative-to, Eric Blake, 2012/03/14
- [PATCH 1/6] test: expose recent gnulib canonicalize bug, Eric Blake, 2012/03/14
- [PATCH 4/6] realpath: let --relative-to default to --relative-base, Eric Blake, 2012/03/14
- [PATCH 3/6] tests: cover more realpath scenarios, Eric Blake, 2012/03/14
- Re: [PATCH 0/6] realpath cleanups, Pádraig Brady, 2012/03/14