2020-12-02 Paul Eggert <eggert@cs.ucla.edu>
+ canonicalize: fix EOVERFLOW bug
+ * lib/canonicalize.c (canonicalize_filename_mode):
+ When testing whether a directory entry is a symbolic link, or a
+ directory or other, do not use lstat or stat or
+ areadlink_with_size. Just use areadlink, as this suffices and it
+ avoids the EOVERFLOW problem that lstat and stat have.
+ * modules/canonicalize (Depends-on): Depend on areadlink instead
+ of areadlink-with-size and stat.
+
canonicalize-lgpl: fix EOVERFLOW bug
* lib/canonicalize-lgpl.c: Do not include <sys/stat.h>.
(__realpath): Do not use lstat. Just use readlink, as this
for (end = start; *end && !ISSLASH (*end); ++end)
/* Nothing. */;
- if (end - start == 0)
- break;
- else if (end - start == 1 && start[0] == '.')
+ if (end - start == 1 && start[0] == '.')
/* nothing */;
else if (end - start == 2 && start[0] == '.' && start[1] == '.')
{
}
else
{
- struct stat st;
-
if (!ISSLASH (dest[-1]))
*dest++ = '/';
dest += end - start;
*dest = '\0';
- if (logical && (can_mode == CAN_MISSING))
- {
- /* Avoid the stat in this case as it's inconsequential.
- i.e. we're neither resolving symlinks or testing
- component existence. */
- st.st_mode = 0;
- }
- else if ((logical ? stat (rname, &st) : lstat (rname, &st)) != 0)
+ char discard;
+ char *buf = logical ? NULL : areadlink (rname);
+ if (buf)
{
- /* FIXME: If errno == EOVERFLOW here, the entry exists. */
- saved_errno = errno;
- if (can_mode == CAN_EXISTING)
- goto error;
- if (can_mode == CAN_ALL_BUT_LAST)
+ /* A physical traversal and RNAME is a symbolic link. */
+ struct stat st;
+ if (lstat (rname, &st) != 0)
{
- if (end[strspn (end, SLASHES)] || saved_errno != ENOENT)
- goto error;
- continue;
+ saved_errno = errno;
+ free (buf);
+ goto error;
}
- st.st_mode = 0;
- }
- if (S_ISLNK (st.st_mode))
- {
- char *buf;
size_t n, len;
/* Detect loops. We cannot use the cycle-check module here,
if (can_mode == CAN_MISSING)
continue;
saved_errno = ELOOP;
- goto error;
- }
-
- buf = areadlink_with_size (rname, st.st_size);
- if (!buf)
- {
- if (can_mode == CAN_MISSING && errno != ENOMEM)
- continue;
- saved_errno = errno;
+ free (buf);
goto error;
}
free (buf);
}
- else
+ else if (can_mode != CAN_MISSING
+ && (!logical || readlink (rname, &discard, 1) < 0))
{
- if (!S_ISDIR (st.st_mode) && *end && (can_mode != CAN_MISSING))
+ saved_errno = errno;
+ switch (saved_errno)
{
- saved_errno = ENOTDIR;
+ case EINVAL:
+ /* RNAME exists and is not symbolic link. */
+ break;
+
+ case ENOENT:
+ /* RNAME does not exist. */
+ if (can_mode == CAN_EXISTING
+ || (can_mode == CAN_ALL_BUT_LAST
+ && end[strspn (end, SLASHES)]))
+ goto error;
+ break;
+
+ default:
+ /* Some other problem with RNAME. */
goto error;
}
}