(root)/
tar-1.35/
gnu/
opendir.c
       1  /* Start reading the entries of a directory.
       2     Copyright (C) 2006-2023 Free Software Foundation, Inc.
       3  
       4     This file is free software: you can redistribute it and/or modify
       5     it under the terms of the GNU Lesser General Public License as
       6     published by the Free Software Foundation; either version 2.1 of the
       7     License, or (at your option) any later version.
       8  
       9     This file is distributed in the hope that it will be useful,
      10     but WITHOUT ANY WARRANTY; without even the implied warranty of
      11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12     GNU Lesser General Public License for more details.
      13  
      14     You should have received a copy of the GNU Lesser General Public License
      15     along with this program.  If not, see <https://www.gnu.org/licenses/>.  */
      16  
      17  #include <config.h>
      18  
      19  /* Specification.  */
      20  #include <dirent.h>
      21  
      22  #include <errno.h>
      23  #include <stddef.h>
      24  
      25  #if HAVE_OPENDIR
      26  
      27  /* Override opendir(), to keep track of the open file descriptors.
      28     Needed because there is a function dirfd().  */
      29  
      30  #else
      31  
      32  # include "filename.h"
      33  
      34  #endif
      35  
      36  #include <stdlib.h>
      37  #include <string.h>
      38  
      39  #if GNULIB_defined_DIR
      40  # include "dirent-private.h"
      41  #endif
      42  
      43  #if REPLACE_FCHDIR
      44  # include <unistd.h>
      45  #endif
      46  
      47  #ifdef __KLIBC__
      48  # include <io.h>
      49  # include <fcntl.h>
      50  #endif
      51  
      52  #if defined _WIN32 && ! defined __CYGWIN__
      53  /* Don't assume that UNICODE is not defined.  */
      54  # undef WIN32_FIND_DATA
      55  # define WIN32_FIND_DATA WIN32_FIND_DATAA
      56  # undef GetFullPathName
      57  # define GetFullPathName GetFullPathNameA
      58  # undef FindFirstFile
      59  # define FindFirstFile FindFirstFileA
      60  #endif
      61  
      62  DIR *
      63  opendir (const char *dir_name)
      64  #undef opendir
      65  {
      66  #if HAVE_DIRENT_H                       /* equivalent to HAVE_OPENDIR */
      67    DIR *dirp;
      68  
      69  # if GNULIB_defined_DIR
      70  #  undef DIR
      71  
      72    dirp = (struct gl_directory *) malloc (sizeof (struct gl_directory));
      73    if (dirp == NULL)
      74      {
      75        errno = ENOMEM;
      76        return NULL;
      77      }
      78  
      79    DIR *real_dirp = opendir (dir_name);
      80    if (real_dirp == NULL)
      81      {
      82        int saved_errno = errno;
      83        free (dirp);
      84        errno = saved_errno;
      85        return NULL;
      86      }
      87  
      88    dirp->fd_to_close = -1;
      89    dirp->real_dirp = real_dirp;
      90  # else
      91    dirp = opendir (dir_name);
      92    if (dirp == NULL)
      93      return NULL;
      94  # endif
      95  
      96  # ifdef __KLIBC__
      97    {
      98      int fd = open (dir_name, O_RDONLY);
      99      if (fd == -1 || _gl_register_dirp_fd (fd, dirp))
     100        {
     101          int saved_errno = errno;
     102  
     103          close (fd);
     104          closedir (dirp);
     105  
     106          errno = saved_errno;
     107  
     108          return NULL;
     109        }
     110    }
     111  # endif
     112  
     113  #else
     114  
     115    char dir_name_mask[MAX_PATH + 1 + 1 + 1];
     116    int status;
     117    HANDLE current;
     118    WIN32_FIND_DATA entry;
     119    struct gl_directory *dirp;
     120  
     121    if (dir_name[0] == '\0')
     122      {
     123        errno = ENOENT;
     124        return NULL;
     125      }
     126  
     127    /* Make the dir_name absolute, so that we continue reading the same
     128       directory if the current directory changed between this opendir()
     129       call and a subsequent rewinddir() call.  */
     130    if (!GetFullPathName (dir_name, MAX_PATH, dir_name_mask, NULL))
     131      {
     132        errno = EINVAL;
     133        return NULL;
     134      }
     135  
     136    /* Append the mask.
     137       "*" and "*.*" appear to be equivalent.  */
     138    {
     139      char *p;
     140  
     141      p = dir_name_mask + strlen (dir_name_mask);
     142      if (p > dir_name_mask && !ISSLASH (p[-1]))
     143        *p++ = '\\';
     144      *p++ = '*';
     145      *p = '\0';
     146    }
     147  
     148    /* Start searching the directory.  */
     149    status = -1;
     150    current = FindFirstFile (dir_name_mask, &entry);
     151    if (current == INVALID_HANDLE_VALUE)
     152      {
     153        switch (GetLastError ())
     154          {
     155          case ERROR_FILE_NOT_FOUND:
     156            status = -2;
     157            break;
     158          case ERROR_PATH_NOT_FOUND:
     159            errno = ENOENT;
     160            return NULL;
     161          case ERROR_DIRECTORY:
     162            errno = ENOTDIR;
     163            return NULL;
     164          case ERROR_ACCESS_DENIED:
     165            errno = EACCES;
     166            return NULL;
     167          default:
     168            errno = EIO;
     169            return NULL;
     170          }
     171      }
     172  
     173    /* Allocate the result.  */
     174    dirp =
     175      (struct gl_directory *)
     176      malloc (offsetof (struct gl_directory, dir_name_mask[0])
     177              + strlen (dir_name_mask) + 1);
     178    if (dirp == NULL)
     179      {
     180        if (current != INVALID_HANDLE_VALUE)
     181          FindClose (current);
     182        errno = ENOMEM;
     183        return NULL;
     184      }
     185    dirp->fd_to_close = -1;
     186    dirp->status = status;
     187    dirp->current = current;
     188    if (status == -1)
     189      memcpy (&dirp->entry, &entry, sizeof (WIN32_FIND_DATA));
     190    strcpy (dirp->dir_name_mask, dir_name_mask);
     191  
     192  #endif
     193  
     194  #if REPLACE_FCHDIR
     195    {
     196      int fd = dirfd (dirp);
     197      if (0 <= fd && _gl_register_fd (fd, dir_name) != fd)
     198        {
     199          int saved_errno = errno;
     200          closedir (dirp);
     201          errno = saved_errno;
     202          return NULL;
     203        }
     204    }
     205  #endif
     206  
     207    return dirp;
     208  }