11573Srgrimes/*
21573Srgrimes * Copyright (c) 1983, 1993
31573Srgrimes *	The Regents of the University of California.  All rights reserved.
41573Srgrimes *
51573Srgrimes * Redistribution and use in source and binary forms, with or without
61573Srgrimes * modification, are permitted provided that the following conditions
71573Srgrimes * are met:
81573Srgrimes * 1. Redistributions of source code must retain the above copyright
91573Srgrimes *    notice, this list of conditions and the following disclaimer.
101573Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
111573Srgrimes *    notice, this list of conditions and the following disclaimer in the
121573Srgrimes *    documentation and/or other materials provided with the distribution.
131573Srgrimes * 4. Neither the name of the University nor the names of its contributors
141573Srgrimes *    may be used to endorse or promote products derived from this software
151573Srgrimes *    without specific prior written permission.
161573Srgrimes *
171573Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
181573Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
191573Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
201573Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
211573Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
221573Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
231573Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
241573Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
251573Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
261573Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
271573Srgrimes * SUCH DAMAGE.
281573Srgrimes */
291573Srgrimes
301573Srgrimes#if defined(LIBC_SCCS) && !defined(lint)
3123658Speterstatic char sccsid[] = "@(#)readdir.c	8.3 (Berkeley) 9/29/94";
321573Srgrimes#endif /* LIBC_SCCS and not lint */
3390039Sobrien#include <sys/cdefs.h>
3490039Sobrien__FBSDID("$FreeBSD: releng/10.3/lib/libc/gen/readdir.c 282979 2015-05-15 15:49:24Z julian $");
351573Srgrimes
3671579Sdeischen#include "namespace.h"
371573Srgrimes#include <sys/param.h>
381573Srgrimes#include <dirent.h>
3953812Salfred#include <errno.h>
4061193Skris#include <string.h>
4153812Salfred#include <pthread.h>
4271579Sdeischen#include "un-namespace.h"
431573Srgrimes
4471579Sdeischen#include "libc_private.h"
45235647Sgleb#include "gen-private.h"
46150065Sstefanf#include "telldir.h"
4771579Sdeischen
481573Srgrimes/*
491573Srgrimes * get next entry in a directory.
501573Srgrimes */
511573Srgrimesstruct dirent *
52178772Skib_readdir_unlocked(dirp, skip)
5369656Sdeischen	DIR *dirp;
54178772Skib	int skip;
551573Srgrimes{
5669656Sdeischen	struct dirent *dp;
57282979Sjulian	long initial_seek;
58282979Sjulian	long initial_loc = 0;
591573Srgrimes
601573Srgrimes	for (;;) {
6123658Speter		if (dirp->dd_loc >= dirp->dd_size) {
6223658Speter			if (dirp->dd_flags & __DTF_READALL)
6323658Speter				return (NULL);
64282979Sjulian			initial_loc = dirp->dd_loc;
65282979Sjulian			dirp->dd_flags &= ~__DTF_SKIPREAD;
6623658Speter			dirp->dd_loc = 0;
6723658Speter		}
68270002Sjhb		if (dirp->dd_loc == 0 &&
69270002Sjhb		    !(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
70282979Sjulian			initial_seek = dirp->dd_seek;
7171579Sdeischen			dirp->dd_size = _getdirentries(dirp->dd_fd,
721573Srgrimes			    dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
731573Srgrimes			if (dirp->dd_size <= 0)
7423658Speter				return (NULL);
75282979Sjulian			_fixtelldir(dirp, initial_seek, initial_loc);
761573Srgrimes		}
77270002Sjhb		dirp->dd_flags &= ~__DTF_SKIPREAD;
781573Srgrimes		dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
7933665Sjb		if ((long)dp & 03L)	/* bogus pointer check */
8023658Speter			return (NULL);
811573Srgrimes		if (dp->d_reclen <= 0 ||
821573Srgrimes		    dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
8323658Speter			return (NULL);
841573Srgrimes		dirp->dd_loc += dp->d_reclen;
85178772Skib		if (dp->d_ino == 0 && skip)
861573Srgrimes			continue;
8723658Speter		if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
8823658Speter			continue;
891573Srgrimes		return (dp);
901573Srgrimes	}
911573Srgrimes}
9253812Salfred
9371579Sdeischenstruct dirent *
9471579Sdeischenreaddir(dirp)
9571579Sdeischen	DIR *dirp;
9671579Sdeischen{
9771579Sdeischen	struct dirent	*dp;
9871579Sdeischen
9971579Sdeischen	if (__isthreaded) {
100174221Sdes		_pthread_mutex_lock(&dirp->dd_lock);
101178772Skib		dp = _readdir_unlocked(dirp, 1);
102174221Sdes		_pthread_mutex_unlock(&dirp->dd_lock);
10371579Sdeischen	}
10471579Sdeischen	else
105178772Skib		dp = _readdir_unlocked(dirp, 1);
10671579Sdeischen	return (dp);
10771579Sdeischen}
10871579Sdeischen
10953812Salfredint
11053812Salfredreaddir_r(dirp, entry, result)
11153812Salfred	DIR *dirp;
11253812Salfred	struct dirent *entry;
11353812Salfred	struct dirent **result;
11453812Salfred{
11553812Salfred	struct dirent *dp;
11669656Sdeischen	int saved_errno;
11753812Salfred
11853892Salfred	saved_errno = errno;
11953812Salfred	errno = 0;
12071579Sdeischen	if (__isthreaded) {
121174221Sdes		_pthread_mutex_lock(&dirp->dd_lock);
122178772Skib		if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
12391330Salfred			memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
124174221Sdes		_pthread_mutex_unlock(&dirp->dd_lock);
12571579Sdeischen	}
126178772Skib	else if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
12791330Salfred		memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
12871579Sdeischen
12953892Salfred	if (errno != 0) {
13071579Sdeischen		if (dp == NULL)
13153892Salfred			return (errno);
13253892Salfred	} else
13353892Salfred		errno = saved_errno;
13453892Salfred
13553892Salfred	if (dp != NULL)
13653872Swes		*result = entry;
13753892Salfred	else
13853812Salfred		*result = NULL;
13953892Salfred
14053892Salfred	return (0);
14153812Salfred}
142