Home | History | Annotate | Line # | Download | only in import
readdir.c revision 1.1.1.2
      1 /* Read the next entry of a directory.
      2    Copyright (C) 2011-2022 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 #include "dirent-private.h"
     26 
     27 /* Don't assume that UNICODE is not defined.  */
     28 #undef FindNextFile
     29 #define FindNextFile FindNextFileA
     30 
     31 struct dirent *
     32 readdir (DIR *dirp)
     33 {
     34   char type;
     35   struct dirent *result;
     36 
     37   /* There is no need to add code to produce entries for "." and "..".
     38      According to the POSIX:2008 section "4.12 Pathname Resolution"
     39      <https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html>
     40      "." and ".." are syntactic entities.
     41      POSIX also says:
     42        "If entries for dot or dot-dot exist, one entry shall be returned
     43         for dot and one entry shall be returned for dot-dot; otherwise,
     44         they shall not be returned."  */
     45 
     46   switch (dirp->status)
     47     {
     48     case -2:
     49       /* End of directory already reached.  */
     50       return NULL;
     51     case -1:
     52       break;
     53     case 0:
     54       if (!FindNextFile (dirp->current, &dirp->entry))
     55         {
     56           switch (GetLastError ())
     57             {
     58             case ERROR_NO_MORE_FILES:
     59               dirp->status = -2;
     60               return NULL;
     61             default:
     62               errno = EIO;
     63               return NULL;
     64             }
     65         }
     66       break;
     67     default:
     68       errno = dirp->status;
     69       return NULL;
     70     }
     71 
     72   dirp->status = 0;
     73 
     74   if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
     75     type = DT_DIR;
     76   else if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
     77     type = DT_LNK;
     78   else if ((dirp->entry.dwFileAttributes
     79             & ~(FILE_ATTRIBUTE_READONLY
     80                 | FILE_ATTRIBUTE_HIDDEN
     81                 | FILE_ATTRIBUTE_SYSTEM
     82                 | FILE_ATTRIBUTE_ARCHIVE
     83                 | FILE_ATTRIBUTE_NORMAL
     84                 | FILE_ATTRIBUTE_TEMPORARY
     85                 | FILE_ATTRIBUTE_SPARSE_FILE
     86                 | FILE_ATTRIBUTE_COMPRESSED
     87                 | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
     88                 | FILE_ATTRIBUTE_ENCRYPTED)) == 0)
     89     /* Devices like COM1, LPT1, NUL would also have the attributes 0x20 but
     90        they cannot occur here.  */
     91     type = DT_REG;
     92   else
     93     type = DT_UNKNOWN;
     94 
     95   /* Reuse the memory of dirp->entry for the result.  */
     96   result =
     97     (struct dirent *)
     98     ((char *) dirp->entry.cFileName - offsetof (struct dirent, d_name[0]));
     99   result->d_type = type;
    100 
    101   return result;
    102 }
    103