Blame sysdeps/posix/readdir.c

Packit Service 82fcde
/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
Packit Service 82fcde
   This file is part of the GNU C Library.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is free software; you can redistribute it and/or
Packit Service 82fcde
   modify it under the terms of the GNU Lesser General Public
Packit Service 82fcde
   License as published by the Free Software Foundation; either
Packit Service 82fcde
   version 2.1 of the License, or (at your option) any later version.
Packit Service 82fcde
Packit Service 82fcde
   The GNU C Library is distributed in the hope that it will be useful,
Packit Service 82fcde
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit Service 82fcde
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit Service 82fcde
   Lesser General Public License for more details.
Packit Service 82fcde
Packit Service 82fcde
   You should have received a copy of the GNU Lesser General Public
Packit Service 82fcde
   License along with the GNU C Library; if not, see
Packit Service 82fcde
   <http://www.gnu.org/licenses/>.  */
Packit Service 82fcde
Packit Service 82fcde
#include <errno.h>
Packit Service 82fcde
#include <limits.h>
Packit Service 82fcde
#include <stddef.h>
Packit Service 82fcde
#include <string.h>
Packit Service 82fcde
#include <dirent.h>
Packit Service 82fcde
#include <unistd.h>
Packit Service 82fcde
#include <sys/types.h>
Packit Service 82fcde
#include <assert.h>
Packit Service 82fcde
Packit Service 82fcde
#include <dirstream.h>
Packit Service 82fcde
Packit Service 82fcde
#ifndef __READDIR
Packit Service 82fcde
# define __READDIR __readdir
Packit Service 82fcde
# define __GETDENTS __getdents
Packit Service 82fcde
# define DIRENT_TYPE struct dirent
Packit Service 82fcde
# define __READDIR_ALIAS
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Read a directory entry from DIRP.  */
Packit Service 82fcde
DIRENT_TYPE *
Packit Service 82fcde
__READDIR (DIR *dirp)
Packit Service 82fcde
{
Packit Service 82fcde
  DIRENT_TYPE *dp;
Packit Service 82fcde
  int saved_errno = errno;
Packit Service 82fcde
Packit Service 82fcde
#if IS_IN (libc)
Packit Service 82fcde
  __libc_lock_lock (dirp->lock);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  do
Packit Service 82fcde
    {
Packit Service 82fcde
      size_t reclen;
Packit Service 82fcde
Packit Service 82fcde
      if (dirp->offset >= dirp->size)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* We've emptied out our buffer.  Refill it.  */
Packit Service 82fcde
Packit Service 82fcde
	  size_t maxread;
Packit Service 82fcde
	  ssize_t bytes;
Packit Service 82fcde
Packit Service 82fcde
#ifndef _DIRENT_HAVE_D_RECLEN
Packit Service 82fcde
	  /* Fixed-size struct; must read one at a time (see below).  */
Packit Service 82fcde
	  maxread = sizeof *dp;
Packit Service 82fcde
#else
Packit Service 82fcde
	  maxread = dirp->allocation;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
	  bytes = __GETDENTS (dirp->fd, dirp->data, maxread);
Packit Service 82fcde
	  if (bytes <= 0)
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* On some systems getdents fails with ENOENT when the
Packit Service 82fcde
		 open directory has been rmdir'd already.  POSIX.1
Packit Service 82fcde
		 requires that we treat this condition like normal EOF.  */
Packit Service 82fcde
	      if (bytes < 0 && errno == ENOENT)
Packit Service 82fcde
		bytes = 0;
Packit Service 82fcde
Packit Service 82fcde
	      /* Don't modifiy errno when reaching EOF.  */
Packit Service 82fcde
	      if (bytes == 0)
Packit Service 82fcde
		__set_errno (saved_errno);
Packit Service 82fcde
	      dp = NULL;
Packit Service 82fcde
	      break;
Packit Service 82fcde
	    }
Packit Service 82fcde
	  dirp->size = (size_t) bytes;
Packit Service 82fcde
Packit Service 82fcde
	  /* Reset the offset into the buffer.  */
Packit Service 82fcde
	  dirp->offset = 0;
Packit Service 82fcde
	}
Packit Service 82fcde
Packit Service 82fcde
      dp = (DIRENT_TYPE *) &dirp->data[dirp->offset];
Packit Service 82fcde
Packit Service 82fcde
#ifdef _DIRENT_HAVE_D_RECLEN
Packit Service 82fcde
      reclen = dp->d_reclen;
Packit Service 82fcde
#else
Packit Service 82fcde
      /* The only version of `struct dirent*' that lacks `d_reclen'
Packit Service 82fcde
	 is fixed-size.  */
Packit Service 82fcde
      assert (sizeof dp->d_name > 1);
Packit Service 82fcde
      reclen = sizeof *dp;
Packit Service 82fcde
      /* The name is not terminated if it is the largest possible size.
Packit Service 82fcde
	 Clobber the following byte to ensure proper null termination.  We
Packit Service 82fcde
	 read jst one entry at a time above so we know that byte will not
Packit Service 82fcde
	 be used later.  */
Packit Service 82fcde
      dp->d_name[sizeof dp->d_name] = '\0';
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
      dirp->offset += reclen;
Packit Service 82fcde
Packit Service 82fcde
#ifdef _DIRENT_HAVE_D_OFF
Packit Service 82fcde
      dirp->filepos = dp->d_off;
Packit Service 82fcde
#else
Packit Service 82fcde
      dirp->filepos += reclen;
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
      /* Skip deleted files.  */
Packit Service 82fcde
    } while (dp->d_ino == 0);
Packit Service 82fcde
Packit Service 82fcde
#if IS_IN (libc)
Packit Service 82fcde
  __libc_lock_unlock (dirp->lock);
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
  return dp;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#ifdef __READDIR_ALIAS
Packit Service 82fcde
weak_alias (__readdir, readdir)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#undef __READDIR
Packit Service 82fcde
#undef __GETDENTS
Packit Service 82fcde
#undef DIRENT_TYPE
Packit Service 82fcde
#undef __READDIR_ALIAS