diff options
Diffstat (limited to 'sysdeps/posix')
-rw-r--r-- | sysdeps/posix/dirstream.h | 2 | ||||
-rw-r--r-- | sysdeps/posix/opendir.c | 1 | ||||
-rw-r--r-- | sysdeps/posix/readdir_r.c | 42 | ||||
-rw-r--r-- | sysdeps/posix/rewinddir.c | 1 |
4 files changed, 34 insertions, 12 deletions
diff --git a/sysdeps/posix/dirstream.h b/sysdeps/posix/dirstream.h index a7a074d357..8e8570dd48 100644 --- a/sysdeps/posix/dirstream.h +++ b/sysdeps/posix/dirstream.h @@ -39,6 +39,8 @@ struct __dirstream off_t filepos; /* Position of next entry to read. */ + int errcode; /* Delayed error code. */ + /* Directory block. */ char data[0] __attribute__ ((aligned (__alignof__ (void*)))); }; diff --git a/sysdeps/posix/opendir.c b/sysdeps/posix/opendir.c index ddfc3a7510..fc05b0f9d7 100644 --- a/sysdeps/posix/opendir.c +++ b/sysdeps/posix/opendir.c @@ -231,6 +231,7 @@ __alloc_dir (int fd, bool close_fd, int flags, const struct stat64 *statp) dirp->size = 0; dirp->offset = 0; dirp->filepos = 0; + dirp->errcode = 0; return dirp; } diff --git a/sysdeps/posix/readdir_r.c b/sysdeps/posix/readdir_r.c index b5a8e2edef..8ed5c3fc91 100644 --- a/sysdeps/posix/readdir_r.c +++ b/sysdeps/posix/readdir_r.c @@ -40,6 +40,7 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) DIRENT_TYPE *dp; size_t reclen; const int saved_errno = errno; + int ret; __libc_lock_lock (dirp->lock); @@ -70,10 +71,10 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) bytes = 0; __set_errno (saved_errno); } + if (bytes < 0) + dirp->errcode = errno; dp = NULL; - /* Reclen != 0 signals that an error occurred. */ - reclen = bytes != 0; break; } dirp->size = (size_t) bytes; @@ -106,29 +107,46 @@ __READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result) dirp->filepos += reclen; #endif - /* Skip deleted files. */ +#ifdef NAME_MAX + if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1) + { + /* The record is very long. It could still fit into the + caller-supplied buffer if we can skip padding at the + end. */ + size_t namelen = _D_EXACT_NAMLEN (dp); + if (namelen <= NAME_MAX) + reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1; + else + { + /* The name is too long. Ignore this file. */ + dirp->errcode = ENAMETOOLONG; + dp->d_ino = 0; + continue; + } + } +#endif + + /* Skip deleted and ignored files. */ } while (dp->d_ino == 0); if (dp != NULL) { -#ifdef GETDENTS_64BIT_ALIGNED - /* The d_reclen value might include padding which is not part of - the DIRENT_TYPE data structure. */ - reclen = MIN (reclen, - offsetof (DIRENT_TYPE, d_name) + sizeof (dp->d_name)); -#endif *result = memcpy (entry, dp, reclen); -#ifdef GETDENTS_64BIT_ALIGNED +#ifdef _DIRENT_HAVE_D_RECLEN entry->d_reclen = reclen; #endif + ret = 0; } else - *result = NULL; + { + *result = NULL; + ret = dirp->errcode; + } __libc_lock_unlock (dirp->lock); - return dp != NULL ? 0 : reclen ? errno : 0; + return ret; } #ifdef __READDIR_R_ALIAS diff --git a/sysdeps/posix/rewinddir.c b/sysdeps/posix/rewinddir.c index 2935a8e5a0..d4991ad43a 100644 --- a/sysdeps/posix/rewinddir.c +++ b/sysdeps/posix/rewinddir.c @@ -33,6 +33,7 @@ rewinddir (dirp) dirp->filepos = 0; dirp->offset = 0; dirp->size = 0; + dirp->errcode = 0; #ifndef NOT_IN_libc __libc_lock_unlock (dirp->lock); #endif |