* lib/fts.c (fts_stat): If lstat fails, report its errno, which may be EOVERFLOW; this is likely more useful than reporting the stat errno. * lib/glob.c (link_stat): Rename from link_exists2_p and return -1/0 instead of 0/1. Caller changed. * lib/glob.c (link_exists_p): * lib/renameat2.c (rename_noreplace, renameat2): * lib/tempname.c (try_nocreate): If errno == EOVERFLOW then the directory entry exists, so do not act as if it does not exist. --- ChangeLog | 12 ++++++++++++ lib/canonicalize-lgpl.c | 2 ++ lib/fts.c | 4 +--- lib/glob.c | 28 ++++++++++++++++------------ lib/renameat2.c | 4 ++-- lib/tempname.c | 2 +- 6 files changed, 34 insertions(+), 18 deletions(-)
diff --git a/ChangeLog b/ChangeLog index a6909f6..5ef4b1d 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,17 @@ 2017-07-30 Paul Eggert <egg...@cs.ucla.edu> + Don't interpret EOVERFLOW to mean nonexistence + * lib/fts.c (fts_stat): If lstat fails, report its errno, which + may be EOVERFLOW; this is likely more useful than reporting the + stat errno. + * lib/glob.c (link_stat): Rename from link_exists2_p and + return -1/0 instead of 0/1. Caller changed. + * lib/glob.c (link_exists_p): + * lib/renameat2.c (rename_noreplace, renameat2): + * lib/tempname.c (try_nocreate): + If errno == EOVERFLOW then the directory entry exists, so do not + act as if it does not exist. + backup-rename: new module It is like backupfile, except it avoids some race conditions, and it does not output to stderr or exit. diff --git a/lib/canonicalize-lgpl.c b/lib/canonicalize-lgpl.c index 34b3711..f76ea4c 100644 --- a/lib/canonicalize-lgpl.c +++ b/lib/canonicalize-lgpl.c @@ -270,6 +270,8 @@ __realpath (const char *name, char *resolved) #endif *dest = '\0'; + /* FIXME: if lstat fails with errno == EOVERFILE, + the entry exists. */ #ifdef _LIBC if (__lxstat64 (_STAT_VER, rpath, &st) < 0) #else diff --git a/lib/fts.c b/lib/fts.c index 790f71c..a870054 100644 --- a/lib/fts.c +++ b/lib/fts.c @@ -1813,7 +1813,6 @@ internal_function fts_stat(FTS *sp, register FTSENT *p, bool follow) { struct stat *sbp = p->fts_statp; - int saved_errno; if (p->fts_level == FTS_ROOTLEVEL && ISSET(FTS_COMFOLLOW)) follow = true; @@ -1825,13 +1824,12 @@ fts_stat(FTS *sp, register FTSENT *p, bool follow) */ if (ISSET(FTS_LOGICAL) || follow) { if (stat(p->fts_accpath, sbp)) { - saved_errno = errno; if (errno == ENOENT && lstat(p->fts_accpath, sbp) == 0) { __set_errno (0); return (FTS_SLNONE); } - p->fts_errno = saved_errno; + p->fts_errno = errno; goto err; } } else if (fstatat(sp->fts_cwd_fd, p->fts_accpath, sbp, diff --git a/lib/glob.c b/lib/glob.c index 3b3194a..d061017 100644 --- a/lib/glob.c +++ b/lib/glob.c @@ -1531,12 +1531,12 @@ weak_alias (__glob_pattern_p, glob_pattern_p) allocated with alloca to be recycled. */ static int __attribute_noinline__ -link_exists2_p (const char *dir, size_t dirlen, const char *fname, - glob_t *pglob +link_stat (const char *dir, size_t dirlen, const char *fname, + glob_t *pglob # if !defined _LIBC && !HAVE_FSTATAT - , int flags + , int flags # endif - ) + ) { size_t fnamelen = strlen (fname); char *fullname = __alloca (dirlen + 1 + fnamelen + 1); @@ -1549,10 +1549,10 @@ link_exists2_p (const char *dir, size_t dirlen, const char *fname, if (__builtin_expect ((flags & GLOB_ALTDIRFUNC) == 0, 1)) { struct_stat64 st64; - return __stat64 (fullname, &st64) == 0; + return __stat64 (fullname, &st64); } # endif - return (*pglob->gl_stat) (fullname, &st) == 0; + return (*pglob->gl_stat) (fullname, &st); } /* Return true if DIR/FNAME exists. */ @@ -1560,19 +1560,21 @@ static int link_exists_p (int dfd, const char *dir, size_t dirlen, const char *fname, glob_t *pglob, int flags) { + int status; # if defined _LIBC || HAVE_FSTATAT if (__builtin_expect (flags & GLOB_ALTDIRFUNC, 0)) - return link_exists2_p (dir, dirlen, fname, pglob); + status = link_stat (dir, dirlen, fname, pglob); else { /* dfd cannot be -1 here, because dirfd never returns -1 on glibc, or on hosts that have fstatat. */ struct_stat64 st64; - return __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0) == 0; + status = __fxstatat64 (_STAT_VER, dfd, fname, &st64, 0); } # else - return link_exists2_p (dir, dirlen, fname, pglob, flags); + status = link_stat (dir, dirlen, fname, pglob, flags); # endif + return status == 0 || errno == EOVERFLOW; } #endif /* !defined GLOB_ONLY_P */ @@ -1643,9 +1645,11 @@ glob_in_dir (const char *pattern, const char *directory, int flags, mempcpy (mempcpy (mempcpy (fullname, directory, dirlen), "/", 1), pattern, patlen + 1); - if ((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) - ? (*pglob->gl_stat) (fullname, &ust.st) - : __stat64 (fullname, &ust.st64)) == 0) + if (((__builtin_expect (flags & GLOB_ALTDIRFUNC, 0) + ? (*pglob->gl_stat) (fullname, &ust.st) + : __stat64 (fullname, &ust.st64)) + == 0) + || errno == EOVERFLOW) /* We found this file to be existing. Now tell the rest of the function to copy this name into the result. */ flags |= GLOB_NOCHECK; diff --git a/lib/renameat2.c b/lib/renameat2.c index 4f9e3d1..60b721c 100644 --- a/lib/renameat2.c +++ b/lib/renameat2.c @@ -53,7 +53,7 @@ rename_noreplace (char const *src, char const *dst) { /* This has a race between the call to lstat and the call to rename. */ struct stat st; - return (lstat (dst, &st) == 0 ? errno_fail (EEXIST) + return (lstat (dst, &st) == 0 || errno == EOVERFLOW ? errno_fail (EEXIST) : errno == ENOENT ? rename (src, dst) : -1); } @@ -103,7 +103,7 @@ renameat2 (int fd1, char const *src, int fd2, char const *dst, { /* This has a race between the call to lstatat and the calls to renameat below. */ - if (lstatat (fd2, dst, &dst_st) == 0) + if (lstatat (fd2, dst, &dst_st) == 0 || errno == EOVERFLOW) return errno_fail (EEXIST); if (errno != ENOENT) return -1; diff --git a/lib/tempname.c b/lib/tempname.c index 2cd9032..9c4a3c2 100644 --- a/lib/tempname.c +++ b/lib/tempname.c @@ -279,7 +279,7 @@ try_nocreate (char *tmpl, void *flags _GL_UNUSED) { struct_stat64 st; - if (__lxstat64 (_STAT_VER, tmpl, &st) == 0) + if (__lxstat64 (_STAT_VER, tmpl, &st) == 0 || errno == EOVERFLOW) __set_errno (EEXIST); return errno == ENOENT ? 0 : -1; } -- 2.7.4