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.
+2011-12-29 Pádraig Brady <P@draigBrady.com>
+
+ 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 <meyering@redhat.com>
gitlog-to-changelog: do not clump multi-paragraph entries
#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
/* 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)
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)
{
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)
#include <stdlib.h> /* for canonicalize_file_name */
+#define CAN_MODE_MASK (CAN_EXISTING | CAN_ALL_BUT_LAST | CAN_MISSING)
+
enum canonicalize_mode_t
{
/* All components must exist. */
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;
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. */
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");