Blame sysdeps/posix/readdir_r.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_R
Packit Service 82fcde
# define __READDIR_R __readdir_r
Packit Service 82fcde
# define __GETDENTS __getdents
Packit Service 82fcde
# define DIRENT_TYPE struct dirent
Packit Service 82fcde
# define __READDIR_R_ALIAS
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
/* Read a directory entry from DIRP.  */
Packit Service 82fcde
int
Packit Service 82fcde
__READDIR_R (DIR *dirp, DIRENT_TYPE *entry, DIRENT_TYPE **result)
Packit Service 82fcde
{
Packit Service 82fcde
  DIRENT_TYPE *dp;
Packit Service 82fcde
  size_t reclen;
Packit Service 82fcde
  const int saved_errno = errno;
Packit Service 82fcde
  int ret;
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_lock (dirp->lock);
Packit Service 82fcde
Packit Service 82fcde
  do
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
		{
Packit Service 82fcde
		  bytes = 0;
Packit Service 82fcde
		  __set_errno (saved_errno);
Packit Service 82fcde
		}
Packit Service 82fcde
	      if (bytes < 0)
Packit Service 82fcde
		dirp->errcode = errno;
Packit Service 82fcde
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 just 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
#ifdef NAME_MAX
Packit Service 82fcde
      if (reclen > offsetof (DIRENT_TYPE, d_name) + NAME_MAX + 1)
Packit Service 82fcde
	{
Packit Service 82fcde
	  /* The record is very long.  It could still fit into the
Packit Service 82fcde
	     caller-supplied buffer if we can skip padding at the
Packit Service 82fcde
	     end.  */
Packit Service 82fcde
	  size_t namelen = _D_EXACT_NAMLEN (dp);
Packit Service 82fcde
	  if (namelen <= NAME_MAX)
Packit Service 82fcde
	    reclen = offsetof (DIRENT_TYPE, d_name) + namelen + 1;
Packit Service 82fcde
	  else
Packit Service 82fcde
	    {
Packit Service 82fcde
	      /* The name is too long.  Ignore this file.  */
Packit Service 82fcde
	      dirp->errcode = ENAMETOOLONG;
Packit Service 82fcde
	      dp->d_ino = 0;
Packit Service 82fcde
	      continue;
Packit Service 82fcde
	    }
Packit Service 82fcde
	}
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
      /* Skip deleted and ignored files.  */
Packit Service 82fcde
    }
Packit Service 82fcde
  while (dp->d_ino == 0);
Packit Service 82fcde
Packit Service 82fcde
  if (dp != NULL)
Packit Service 82fcde
    {
Packit Service 82fcde
      *result = memcpy (entry, dp, reclen);
Packit Service 82fcde
#ifdef _DIRENT_HAVE_D_RECLEN
Packit Service 82fcde
      entry->d_reclen = reclen;
Packit Service 82fcde
#endif
Packit Service 82fcde
      ret = 0;
Packit Service 82fcde
    }
Packit Service 82fcde
  else
Packit Service 82fcde
    {
Packit Service 82fcde
      *result = NULL;
Packit Service 82fcde
      ret = dirp->errcode;
Packit Service 82fcde
    }
Packit Service 82fcde
Packit Service 82fcde
  __libc_lock_unlock (dirp->lock);
Packit Service 82fcde
Packit Service 82fcde
  return ret;
Packit Service 82fcde
}
Packit Service 82fcde
Packit Service 82fcde
#ifdef __READDIR_R_ALIAS
Packit Service 82fcde
weak_alias (__readdir_r, readdir_r)
Packit Service 82fcde
#endif
Packit Service 82fcde
Packit Service 82fcde
#undef __READDIR_R
Packit Service 82fcde
#undef __GETDENTS
Packit Service 82fcde
#undef DIRENT_TYPE
Packit Service 82fcde
#undef __READDIR_R_ALIAS