From: Pádraig Brady
Date: Thu, 29 Dec 2011 23:49:53 +0000 (+0000)
Subject: canonicalize: add support for not resolving symlinks
X-Git-Tag: v0.1~1333
X-Git-Url: http://erislabs.org.uk/gitweb/?a=commitdiff_plain;h=8bcd0399386f6c3298ee63da74c58f80053d5a42;p=gnulib.git
canonicalize: add support for not resolving symlinks
This will initially be used by a new coreutils realpath command.
* lib/canonicalize.h: Add the CAN_NOLINKS flag to
indicate we don't want to follow symlinks. Also
provide CAN_MODE_MASK to aid setting these existing
mutually exclusive values.
* lib/canonicalize.c (canonicalize_filename_mode):
Extract the flags from can_mode parameter, which
are currently just used to select between stat()
and lstat(). Also ensure that mutually exclusive
values are flagged immediately as invalid.
* tests/test-canonicalize.c: Verify symlinks are
not followed, and that invalid flag combinations
are diagnosed.
---
diff --git a/ChangeLog b/ChangeLog
index cc50b4add..fe9696674 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2011-12-29 Pádraig Brady
+
+ canonicalize: add support for not resolving symlinks
+ * lib/canonicalize.h: Add the CAN_NOLINKS flag to
+ indicate we don't want to follow symlinks. Also
+ provide CAN_MODE_MASK to aid setting these existing
+ mutually exclusive values.
+ * lib/canonicalize.c (canonicalize_filename_mode):
+ Extract the flags from can_mode parameter, which
+ are currently just used to select between stat()
+ and lstat(). Also ensure that mutually exclusive
+ values are flagged immediately as invalid.
+ * tests/test-canonicalize.c: Verify symlinks are
+ not followed, and that invalid flag combinations
+ are diagnosed.
+
2011-12-25 Jim Meyering
gitlog-to-changelog: do not clump multi-paragraph entries
diff --git a/lib/canonicalize.c b/lib/canonicalize.c
index 4fe9f308a..a5c9cb4a5 100644
--- a/lib/canonicalize.c
+++ b/lib/canonicalize.c
@@ -31,6 +31,8 @@
#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
@@ -82,8 +84,9 @@ 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. */
+ separators ('/') or, depdending 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)
@@ -95,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)
{
@@ -185,7 +198,7 @@ canonicalize_filename_mode (const char *name, canonicalize_mode_t can_mode)
dest += end - start;
*dest = '\0';
- if (lstat (rname, &st) != 0)
+ if ((logical ? stat : lstat) (rname, &st) != 0)
{
saved_errno = errno;
if (can_mode == CAN_EXISTING)
diff --git a/lib/canonicalize.h b/lib/canonicalize.h
index 04ad79cee..1887b72a2 100644
--- a/lib/canonicalize.h
+++ b/lib/canonicalize.h
@@ -19,6 +19,8 @@
#include /* for canonicalize_file_name */
+#define CAN_MODE_MASK (CAN_EXISTING | CAN_ALL_BUT_LAST | CAN_MISSING)
+
enum canonicalize_mode_t
{
/* All components must exist. */
@@ -28,7 +30,10 @@ enum canonicalize_mode_t
CAN_ALL_BUT_LAST = 1,
/* No requirements on components existence. */
- CAN_MISSING = 2
+ CAN_MISSING = 2,
+
+ /* Don't expand symlinks. */
+ CAN_NOLINKS = 4
};
typedef enum canonicalize_mode_t canonicalize_mode_t;
diff --git a/tests/test-canonicalize.c b/tests/test-canonicalize.c
index a095e0e88..9f1b87667 100644
--- a/tests/test-canonicalize.c
+++ b/tests/test-canonicalize.c
@@ -82,6 +82,9 @@ main (void)
result2 = canonicalize_filename_mode (NULL, CAN_EXISTING);
ASSERT (result2 == NULL);
ASSERT (errno == EINVAL);
+ result2 = canonicalize_filename_mode (".", CAN_MISSING | CAN_ALL_BUT_LAST);
+ ASSERT (result2 == NULL);
+ ASSERT (errno == EINVAL);
}
/* Check that a non-directory with trailing slash yields NULL. */
@@ -134,6 +137,15 @@ main (void)
ASSERT (symlink ("../s/2", BASE "/d/1") == 0);
ASSERT (symlink ("//.//../..", BASE "/droot") == 0);
+ /* Check that symbolic links are not resolved, with CAN_NOLINKS. */
+ {
+ char *result1 = canonicalize_filename_mode (BASE "/huk", CAN_NOLINKS);
+ ASSERT (result1 != NULL);
+ ASSERT (strcmp (result1 + strlen (result1) - strlen ("/" BASE "/huk"),
+ "/" BASE "/huk") == 0);
+ free (result1);
+ }
+
/* Check that the symbolic link to a file can be resolved. */
{
char *result1 = canonicalize_file_name (BASE "/huk");