dirfd.c 2.27 KB
Newer Older
Paul Eggert's avatar
Paul Eggert committed
1 2
/* dirfd.c -- return the file descriptor associated with an open DIR*

Paul Eggert's avatar
Paul Eggert committed
3
   Copyright (C) 2001, 2006, 2008-2019 Free Software Foundation, Inc.
Paul Eggert's avatar
Paul Eggert committed
4 5 6 7 8 9 10 11 12 13 14 15

   This program is free software: you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
Paul Eggert's avatar
Paul Eggert committed
16
   along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
Paul Eggert's avatar
Paul Eggert committed
17 18 19 20 21 22 23 24

/* Written by Jim Meyering. */

#include <config.h>

#include <dirent.h>
#include <errno.h>

Paul Eggert's avatar
Paul Eggert committed
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
#ifdef __KLIBC__
# include <stdlib.h>
# include <io.h>

static struct dirp_fd_list
{
  DIR *dirp;
  int fd;
  struct dirp_fd_list *next;
} *dirp_fd_start = NULL;

/* Register fd associated with dirp to dirp_fd_list. */
int
_gl_register_dirp_fd (int fd, DIR *dirp)
{
  struct dirp_fd_list *new_dirp_fd = malloc (sizeof *new_dirp_fd);
  if (!new_dirp_fd)
    return -1;

  new_dirp_fd->dirp = dirp;
  new_dirp_fd->fd = fd;
  new_dirp_fd->next = dirp_fd_start;

  dirp_fd_start = new_dirp_fd;

  return 0;
}

/* Unregister fd from dirp_fd_list with closing it */
void
_gl_unregister_dirp_fd (int fd)
{
  struct dirp_fd_list *dirp_fd;
  struct dirp_fd_list *dirp_fd_prev;

  for (dirp_fd_prev = NULL, dirp_fd = dirp_fd_start; dirp_fd;
       dirp_fd_prev = dirp_fd, dirp_fd = dirp_fd->next)
    {
      if (dirp_fd->fd == fd)
        {
          if (dirp_fd_prev)
            dirp_fd_prev->next = dirp_fd->next;
          else  /* dirp_fd == dirp_fd_start */
            dirp_fd_start = dirp_fd_start->next;

          close (fd);
          free (dirp_fd);
          break;
        }
    }
}
#endif

Paul Eggert's avatar
Paul Eggert committed
78 79 80 81 82
int
dirfd (DIR *dir_p)
{
  int fd = DIR_TO_FD (dir_p);
  if (fd == -1)
Paul Eggert's avatar
Paul Eggert committed
83
#ifndef __KLIBC__
Paul Eggert's avatar
Paul Eggert committed
84
    errno = ENOTSUP;
Paul Eggert's avatar
Paul Eggert committed
85 86 87 88 89 90 91 92 93 94 95 96
#else
    {
      struct dirp_fd_list *dirp_fd;

      for (dirp_fd = dirp_fd_start; dirp_fd; dirp_fd = dirp_fd->next)
        if (dirp_fd->dirp == dir_p)
          return dirp_fd->fd;

      errno = EINVAL;
    }
#endif

Paul Eggert's avatar
Paul Eggert committed
97 98
  return fd;
}