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/11.0/lib/libc/gen/readdir.c 288029 2015-09-20 20:23:16Z rodrigc $");
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 *
52288029Srodrigc_readdir_unlocked(DIR *dirp, int skip)
531573Srgrimes{
5469656Sdeischen	struct dirent *dp;
55282485Sjulian	long initial_seek;
56282485Sjulian	long initial_loc = 0;
571573Srgrimes
581573Srgrimes	for (;;) {
5923658Speter		if (dirp->dd_loc >= dirp->dd_size) {
6023658Speter			if (dirp->dd_flags & __DTF_READALL)
6123658Speter				return (NULL);
62282485Sjulian			initial_loc = dirp->dd_loc;
63282485Sjulian			dirp->dd_flags &= ~__DTF_SKIPREAD;
6423658Speter			dirp->dd_loc = 0;
6523658Speter		}
66268531Sjhb		if (dirp->dd_loc == 0 &&
67268531Sjhb		    !(dirp->dd_flags & (__DTF_READALL | __DTF_SKIPREAD))) {
68282485Sjulian			initial_seek = dirp->dd_seek;
6971579Sdeischen			dirp->dd_size = _getdirentries(dirp->dd_fd,
701573Srgrimes			    dirp->dd_buf, dirp->dd_len, &dirp->dd_seek);
711573Srgrimes			if (dirp->dd_size <= 0)
7223658Speter				return (NULL);
73282485Sjulian			_fixtelldir(dirp, initial_seek, initial_loc);
741573Srgrimes		}
75268531Sjhb		dirp->dd_flags &= ~__DTF_SKIPREAD;
761573Srgrimes		dp = (struct dirent *)(dirp->dd_buf + dirp->dd_loc);
7733665Sjb		if ((long)dp & 03L)	/* bogus pointer check */
7823658Speter			return (NULL);
791573Srgrimes		if (dp->d_reclen <= 0 ||
801573Srgrimes		    dp->d_reclen > dirp->dd_len + 1 - dirp->dd_loc)
8123658Speter			return (NULL);
821573Srgrimes		dirp->dd_loc += dp->d_reclen;
83178772Skib		if (dp->d_ino == 0 && skip)
841573Srgrimes			continue;
8523658Speter		if (dp->d_type == DT_WHT && (dirp->dd_flags & DTF_HIDEW))
8623658Speter			continue;
871573Srgrimes		return (dp);
881573Srgrimes	}
891573Srgrimes}
9053812Salfred
9171579Sdeischenstruct dirent *
92288029Srodrigcreaddir(DIR *dirp)
9371579Sdeischen{
9471579Sdeischen	struct dirent	*dp;
9571579Sdeischen
9671579Sdeischen	if (__isthreaded) {
97174221Sdes		_pthread_mutex_lock(&dirp->dd_lock);
98178772Skib		dp = _readdir_unlocked(dirp, 1);
99174221Sdes		_pthread_mutex_unlock(&dirp->dd_lock);
10071579Sdeischen	}
10171579Sdeischen	else
102178772Skib		dp = _readdir_unlocked(dirp, 1);
10371579Sdeischen	return (dp);
10471579Sdeischen}
10571579Sdeischen
10653812Salfredint
107288029Srodrigcreaddir_r(DIR *dirp, struct dirent *entry, struct dirent **result)
10853812Salfred{
10953812Salfred	struct dirent *dp;
11069656Sdeischen	int saved_errno;
11153812Salfred
11253892Salfred	saved_errno = errno;
11353812Salfred	errno = 0;
11471579Sdeischen	if (__isthreaded) {
115174221Sdes		_pthread_mutex_lock(&dirp->dd_lock);
116178772Skib		if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
11791330Salfred			memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
118174221Sdes		_pthread_mutex_unlock(&dirp->dd_lock);
11971579Sdeischen	}
120178772Skib	else if ((dp = _readdir_unlocked(dirp, 1)) != NULL)
12191330Salfred		memcpy(entry, dp, _GENERIC_DIRSIZ(dp));
12271579Sdeischen
12353892Salfred	if (errno != 0) {
12471579Sdeischen		if (dp == NULL)
12553892Salfred			return (errno);
12653892Salfred	} else
12753892Salfred		errno = saved_errno;
12853892Salfred
12953892Salfred	if (dp != NULL)
13053872Swes		*result = entry;
13153892Salfred	else
13253812Salfred		*result = NULL;
13353892Salfred
13453892Salfred	return (0);
13553812Salfred}
136