2020-12-13 Paul Eggert <eggert@cs.ucla.edu>
+ canonicalize: fix AIX test failures
+ Problem reported by Bruno Haible in:
+ https://lists.gnu.org/r/bug-gnulib/2020-12/msg00109.html
+ * lib/canonicalize.c (canonicalize_filename_mode):
+ When testing a file name ending in '/', use stat rather than
+ readlink, so that it does the right thing on AIX.
+ * modules/canonicalize (Depends-on): Add readlink, to pull in the
+ recent changes in the Gnulib readlink module.
+
Assume readlink/readlinkat ERANGE fix
* lib/areadlink-with-size.c (areadlink_with_size):
* lib/areadlinkat-with-size.c (areadlinkat_with_size):
for (end = start; *end && !ISSLASH (*end); ++end)
/* Nothing. */;
- if (end - start == 1 && start[0] == '.')
+ /* Length of this file name component; it can be zero if a file
+ name ends in '/'. */
+ idx_t startlen = end - start;
+
+ if (startlen == 1 && start[0] == '.')
/* nothing */;
- else if (end - start == 2 && start[0] == '.' && start[1] == '.')
+ else if (startlen == 2 && start[0] == '.' && start[1] == '.')
{
/* Back up to previous component, ignore if at root already. */
if (dest > rname + prefix_len + 1)
if (!ISSLASH (dest[-1]))
*dest++ = '/';
- if (rname_limit - dest <= end - start)
+ if (rname_limit - dest <= startlen)
{
idx_t dest_offset = dest - rname;
idx_t new_size = rname_limit - rname;
- if (end - start + 1 > PATH_MAX)
- new_size += end - start + 1;
- else
- new_size += PATH_MAX;
+ new_size = startlen + 1 <= PATH_MAX ? startlen + 1 : PATH_MAX;
rname = xrealloc (rname, new_size);
rname_limit = rname + new_size;
dest = rname + dest_offset;
}
- dest = memcpy (dest, start, end - start);
- dest += end - start;
+ dest = memcpy (dest, start, startlen);
+ dest += startlen;
*dest = '\0';
+ /* If STARTLEN == 0, RNAME ends in '/'; use stat rather than
+ readlink, because readlink might fail with EINVAL without
+ checking whether RNAME sans '/' is valid. */
char discard;
- char *buf = logical ? NULL : areadlink (rname);
+ struct stat st;
+ char *buf = logical || startlen == 0 ? NULL : areadlink (rname);
if (buf)
{
/* A physical traversal and RNAME is a symbolic link. */
Get the device and inode of the parent directory, as
pre-2017 POSIX says this info is not reliable for
symlinks. */
- dest[- (end - start)] = '\0';
- struct stat st;
+ dest[- startlen] = '\0';
if (stat (*rname ? rname : ".", &st) != 0)
{
saved_errno = errno;
free (buf);
goto error;
}
- dest[- (end - start)] = *start;
+ dest[- startlen] = *start;
/* Detect loops. We cannot use the cycle-check module here,
since it's possible to encounter the same parent
free (buf);
}
else if (can_exist != CAN_MISSING
- && (!logical || readlink (rname, &discard, 1) < 0))
+ && (startlen == 0
+ ? stat (rname, &st) < 0
+ : !logical && readlink (rname, &discard, 1) < 0))
{
saved_errno = errno;
switch (saved_errno)
{
case EINVAL:
- /* RNAME exists and is not symbolic link. */
+ case EOVERFLOW: /* Possible with stat. */
+ /* RNAME exists and is not a symbolic link. */
break;
case ENOENT: