(root)/
tar-1.35/
gnu/
dirfd.c
       1  /* dirfd.c -- return the file descriptor associated with an open DIR*
       2  
       3     Copyright (C) 2001, 2006, 2008-2023 Free Software Foundation, Inc.
       4  
       5     This file is free software: you can redistribute it and/or modify
       6     it under the terms of the GNU Lesser General Public License as
       7     published by the Free Software Foundation; either version 2.1 of the
       8     License, or (at your option) any later version.
       9  
      10     This file 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 Lesser General Public License for more details.
      14  
      15     You should have received a copy of the GNU Lesser General Public License
      16     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      17  
      18  /* Written by Jim Meyering. */
      19  
      20  #include <config.h>
      21  
      22  #include <dirent.h>
      23  #include <errno.h>
      24  
      25  #if GNULIB_defined_DIR
      26  # include "dirent-private.h"
      27  #endif
      28  
      29  #ifdef __KLIBC__
      30  # include <stdlib.h>
      31  # include <io.h>
      32  
      33  static struct dirp_fd_list
      34  {
      35    DIR *dirp;
      36    int fd;
      37    struct dirp_fd_list *next;
      38  } *dirp_fd_start = NULL;
      39  
      40  /* Register fd associated with dirp to dirp_fd_list. */
      41  int
      42  _gl_register_dirp_fd (int fd, DIR *dirp)
      43  {
      44    struct dirp_fd_list *new_dirp_fd = malloc (sizeof *new_dirp_fd);
      45    if (!new_dirp_fd)
      46      return -1;
      47  
      48    new_dirp_fd->dirp = dirp;
      49    new_dirp_fd->fd = fd;
      50    new_dirp_fd->next = dirp_fd_start;
      51  
      52    dirp_fd_start = new_dirp_fd;
      53  
      54    return 0;
      55  }
      56  
      57  /* Unregister fd from dirp_fd_list with closing it */
      58  void
      59  _gl_unregister_dirp_fd (int fd)
      60  {
      61    struct dirp_fd_list *dirp_fd;
      62    struct dirp_fd_list *dirp_fd_prev;
      63  
      64    for (dirp_fd_prev = NULL, dirp_fd = dirp_fd_start; dirp_fd;
      65         dirp_fd_prev = dirp_fd, dirp_fd = dirp_fd->next)
      66      {
      67        if (dirp_fd->fd == fd)
      68          {
      69            if (dirp_fd_prev)
      70              dirp_fd_prev->next = dirp_fd->next;
      71            else  /* dirp_fd == dirp_fd_start */
      72              dirp_fd_start = dirp_fd_start->next;
      73  
      74            close (fd);
      75            free (dirp_fd);
      76            break;
      77          }
      78      }
      79  }
      80  #endif
      81  
      82  int
      83  dirfd (DIR *dir_p)
      84  {
      85  #if GNULIB_defined_DIR
      86    int fd = dir_p->fd_to_close;
      87    if (fd == -1)
      88      errno = EINVAL;
      89    return fd;
      90  #else
      91    int fd = DIR_TO_FD (dir_p);
      92    if (fd == -1)
      93  # ifndef __KLIBC__
      94      errno = ENOTSUP;
      95  # else
      96      {
      97        struct dirp_fd_list *dirp_fd;
      98  
      99        for (dirp_fd = dirp_fd_start; dirp_fd; dirp_fd = dirp_fd->next)
     100          if (dirp_fd->dirp == dir_p)
     101            return dirp_fd->fd;
     102  
     103        errno = EINVAL;
     104      }
     105  # endif
     106  
     107    return fd;
     108  #endif
     109  }