Merge branch 'vendor/GREP'
[dragonfly.git] / contrib / grep / lib / readdir.c
1 /* Read the next entry of a directory.
2    Copyright (C) 2011-2015 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program 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 General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://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 struct dirent *
28 readdir (DIR *dirp)
29 {
30   char type;
31   struct dirent *result;
32
33   /* There is no need to add code to produce entries for "." and "..".
34      According to the POSIX:2008 section "4.12 Pathname Resolution"
35      <http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap04.html>
36      "." and ".." are syntactic entities.
37      POSIX also says:
38        "If entries for dot or dot-dot exist, one entry shall be returned
39         for dot and one entry shall be returned for dot-dot; otherwise,
40         they shall not be returned."  */
41
42   switch (dirp->status)
43     {
44     case -2:
45       /* End of directory already reached.  */
46       return NULL;
47     case -1:
48       break;
49     case 0:
50       if (!FindNextFile (dirp->current, &dirp->entry))
51         {
52           switch (GetLastError ())
53             {
54             case ERROR_NO_MORE_FILES:
55               dirp->status = -2;
56               return NULL;
57             default:
58               errno = EIO;
59               return NULL;
60             }
61         }
62       break;
63     default:
64       errno = dirp->status;
65       return NULL;
66     }
67
68   dirp->status = 0;
69
70   if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
71     type = DT_DIR;
72   else if (dirp->entry.dwFileAttributes & FILE_ATTRIBUTE_REPARSE_POINT)
73     type = DT_LNK;
74   else if ((dirp->entry.dwFileAttributes
75             & ~(FILE_ATTRIBUTE_READONLY
76                 | FILE_ATTRIBUTE_HIDDEN
77                 | FILE_ATTRIBUTE_SYSTEM
78                 | FILE_ATTRIBUTE_ARCHIVE
79                 | FILE_ATTRIBUTE_NORMAL
80                 | FILE_ATTRIBUTE_TEMPORARY
81                 | FILE_ATTRIBUTE_SPARSE_FILE
82                 | FILE_ATTRIBUTE_COMPRESSED
83                 | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED
84                 | FILE_ATTRIBUTE_ENCRYPTED)) == 0)
85     /* Devices like COM1, LPT1, NUL would also have the attributes 0x20 but
86        they cannot occur here.  */
87     type = DT_REG;
88   else
89     type = DT_UNKNOWN;
90
91   /* Reuse the memory of dirp->entry for the result.  */
92   result =
93     (struct dirent *)
94     ((char *) dirp->entry.cFileName - offsetof (struct dirent, d_name[0]));
95   result->d_type = type;
96
97   return result;
98 }