Module Name: src Committed By: riastradh Date: Tue Sep 10 17:11:19 UTC 2024
Modified Files: src/lib/libc/gen: readdir.c Log Message: readdir(3): Preserve errno on end-of-directory. PR pkg/57145: gmake: *** INTERNAL: readdir: Operation not supported. Stop. To generate a diff of this commit: cvs rdiff -u -r1.26 -r1.27 src/lib/libc/gen/readdir.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/gen/readdir.c diff -u src/lib/libc/gen/readdir.c:1.26 src/lib/libc/gen/readdir.c:1.27 --- src/lib/libc/gen/readdir.c:1.26 Mon Jun 25 22:32:43 2012 +++ src/lib/libc/gen/readdir.c Tue Sep 10 17:11:19 2024 @@ -1,4 +1,4 @@ -/* $NetBSD: readdir.c,v 1.26 2012/06/25 22:32:43 abs Exp $ */ +/* $NetBSD: readdir.c,v 1.27 2024/09/10 17:11:19 riastradh Exp $ */ /* * Copyright (c) 1983, 1993 @@ -34,7 +34,7 @@ #if 0 static char sccsid[] = "@(#)readdir.c 8.3 (Berkeley) 9/29/94"; #else -__RCSID("$NetBSD: readdir.c,v 1.26 2012/06/25 22:32:43 abs Exp $"); +__RCSID("$NetBSD: readdir.c,v 1.27 2024/09/10 17:11:19 riastradh Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -56,35 +56,50 @@ __RCSID("$NetBSD: readdir.c,v 1.26 2012/ struct dirent * _readdir_unlocked(DIR *dirp, int skipdeleted) { + const int saved_errno = errno; struct dirent *dp; for (;;) { if (dirp->dd_loc >= dirp->dd_size) { if (dirp->dd_flags & __DTF_READALL) - return (NULL); + break; dirp->dd_loc = 0; } if (dirp->dd_loc == 0 && !(dirp->dd_flags & __DTF_READALL)) { dirp->dd_seek = lseek(dirp->dd_fd, (off_t)0, SEEK_CUR); dirp->dd_size = getdents(dirp->dd_fd, dirp->dd_buf, (size_t)dirp->dd_len); - if (dirp->dd_size <= 0) - return (NULL); + if (dirp->dd_size == 0) /* end of directory */ + break; + if (dirp->dd_size == -1) /* getdents sets errno */ + return NULL; + if (dirp->dd_size < 0) { /* paranoia */ + errno = EIO; + return NULL; + } } dp = (struct dirent *) (void *)(dirp->dd_buf + (size_t)dirp->dd_loc); - if ((intptr_t)dp & _DIRENT_ALIGN(dp))/* bogus pointer check */ - return (NULL); + /* bogus pointer check */ + if ((intptr_t)dp & _DIRENT_ALIGN(dp)) { + errno = EIO; + return NULL; + } /* d_reclen is unsigned; no need to compare it <= 0 */ - if (dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc) - return (NULL); + if (dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc) { + errno = EIO; + return NULL; + } dirp->dd_loc += dp->d_reclen; if (dp->d_ino == 0 && skipdeleted) continue; if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW)) continue; - return (dp); + return dp; } + + errno = saved_errno; + return NULL; } struct dirent *