(root)/
tar-1.35/
gnu/
opendir-safer.c
       1  /* Invoke opendir, but avoid some glitches.
       2  
       3     Copyright (C) 2009-2023 Free Software Foundation, Inc.
       4  
       5     This program is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU General Public License as published by
       7     the Free Software Foundation, either version 3 of the License, or
       8     (at your option) any later version.
       9  
      10     This program is distributed in the hope that it will be useful,
      11     but WITHOUT ANY WARRANTY; without even the implied warranty of
      12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      13     GNU General Public License for more details.
      14  
      15     You should have received a copy of the GNU General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Written by Eric Blake.  */
      19  
      20  #include <config.h>
      21  
      22  #include "dirent-safer.h"
      23  
      24  #include <errno.h>
      25  #include <fcntl.h>
      26  #include <unistd.h>
      27  
      28  /* Like opendir, but do not clobber stdin, stdout, or stderr.  */
      29  
      30  DIR *
      31  opendir_safer (char const *name)
      32  {
      33    DIR *dp = opendir (name);
      34  
      35    if (dp)
      36      {
      37        int fd = dirfd (dp);
      38  
      39        if (0 <= fd && fd <= STDERR_FILENO)
      40          {
      41            /* If fdopendir is native (as on Linux), then it is safe to
      42               assume dirfd(fdopendir(n))==n.  If we are using the
      43               gnulib module fdopendir, then this guarantee is not met,
      44               but fdopendir recursively calls opendir_safer up to 3
      45               times to at least get a safe fd.  If fdopendir is not
      46               present but dirfd is accurate (as on cygwin 1.5.x), then
      47               we recurse up to 3 times ourselves.  Finally, if dirfd
      48               always fails (as on mingw), then we are already safe.  */
      49            DIR *newdp;
      50            int e;
      51  #if HAVE_FDOPENDIR || GNULIB_FDOPENDIR
      52            int f = fcntl (fd, F_DUPFD_CLOEXEC, STDERR_FILENO + 1);
      53            if (f < 0)
      54              {
      55                e = errno;
      56                newdp = NULL;
      57              }
      58            else
      59              {
      60                newdp = fdopendir (f);
      61                e = errno;
      62                if (! newdp)
      63                  close (f);
      64              }
      65  #else /* !FDOPENDIR */
      66            newdp = opendir_safer (name);
      67            e = errno;
      68  #endif
      69            closedir (dp);
      70            errno = e;
      71            dp = newdp;
      72          }
      73      }
      74  
      75    return dp;
      76  }