xref: /netbsd-src/external/gpl3/gcc/dist/libstdc++-v3/src/filesystem/dir-common.h (revision 7330f729ccf0bd976a06f95fad452fe774fc7fd1)
1 // Filesystem directory iterator utilities -*- C++ -*-
2 
3 // Copyright (C) 2014-2018 Free Software Foundation, Inc.
4 //
5 // This file is part of the GNU ISO C++ Library.  This library is free
6 // software; you can redistribute it and/or modify it under the
7 // terms of the GNU General Public License as published by the
8 // Free Software Foundation; either version 3, or (at your option)
9 // any later version.
10 
11 // This library is distributed in the hope that it will be useful,
12 // but WITHOUT ANY WARRANTY; without even the implied warranty of
13 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 // GNU General Public License for more details.
15 
16 // Under Section 7 of GPL version 3, you are granted additional
17 // permissions described in the GCC Runtime Library Exception, version
18 // 3.1, as published by the Free Software Foundation.
19 
20 // You should have received a copy of the GNU General Public License and
21 // a copy of the GCC Runtime Library Exception along with this program;
22 // see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
23 // <http://www.gnu.org/licenses/>.
24 
25 #ifndef _GLIBCXX_DIR_COMMON_H
26 #define _GLIBCXX_DIR_COMMON_H 1
27 
28 #include <string.h>  // strcmp
29 #ifdef _GLIBCXX_HAVE_DIRENT_H
30 # ifdef _GLIBCXX_HAVE_SYS_TYPES_H
31 #  include <sys/types.h>
32 # endif
33 # include <dirent.h>
34 #else
35 # error "the <dirent.h> header is needed to build the Filesystem TS"
36 #endif
37 
38 #ifdef _GLIBCXX_FILESYSTEM_IS_WINDOWS
39 # undef opendir
40 # define opendir _wopendir
41 #endif
42 
43 namespace std _GLIBCXX_VISIBILITY(default)
44 {
45 _GLIBCXX_BEGIN_NAMESPACE_VERSION
46 namespace filesystem
47 {
48 
49 struct _Dir_base
50 {
51   _Dir_base(DIR* dirp = nullptr) : dirp(dirp) { }
52 
53   // If no error occurs then dirp is non-null,
54   // otherwise null (whether error ignored or not).
55   _Dir_base(const char* p, bool skip_permission_denied,
56 	    error_code& ec) noexcept
57   : dirp(::opendir(p))
58   {
59     if (dirp)
60       ec.clear();
61     else
62     {
63       const int err = errno;
64       if (err == EACCES && skip_permission_denied)
65 	ec.clear();
66       else
67 	ec.assign(err, std::generic_category());
68     }
69   }
70 
71   _Dir_base(_Dir_base&& d) : dirp(std::exchange(d.dirp, nullptr)) { }
72 
73   _Dir_base& operator=(_Dir_base&&) = delete;
74 
75   ~_Dir_base() { if (dirp) ::closedir(dirp); }
76 
77   const struct ::dirent*
78   advance(bool skip_permission_denied, error_code& ec) noexcept
79   {
80     ec.clear();
81 
82     int err = std::exchange(errno, 0);
83     const struct ::dirent* entp = readdir(dirp);
84     // std::swap cannot be used with Bionic's errno
85     err = std::exchange(errno, err);
86 
87     if (entp)
88       {
89 	// skip past dot and dot-dot
90 	if (!strcmp(entp->d_name, ".") || !strcmp(entp->d_name, ".."))
91 	  return advance(skip_permission_denied, ec);
92 	return entp;
93       }
94     else if (err)
95       {
96 	if (err == EACCES && skip_permission_denied)
97 	  return nullptr;
98 	ec.assign(err, std::generic_category());
99 	return nullptr;
100       }
101     else
102       {
103 	// reached the end
104 	return nullptr;
105       }
106   }
107 
108   DIR*	dirp;
109 };
110 
111 } // namespace filesystem
112 
113 // BEGIN/END macros must be defined before including this file.
114 _GLIBCXX_BEGIN_NAMESPACE_FILESYSTEM
115 inline file_type
116 get_file_type(const ::dirent& d __attribute__((__unused__)))
117 {
118 #ifdef _GLIBCXX_HAVE_STRUCT_DIRENT_D_TYPE
119   switch (d.d_type)
120   {
121   case DT_BLK:
122     return file_type::block;
123   case DT_CHR:
124     return file_type::character;
125   case DT_DIR:
126     return file_type::directory;
127   case DT_FIFO:
128     return file_type::fifo;
129   case DT_LNK:
130     return file_type::symlink;
131   case DT_REG:
132     return file_type::regular;
133   case DT_SOCK:
134     return file_type::socket;
135   case DT_UNKNOWN:
136     return file_type::unknown;
137   default:
138     return file_type::none;
139   }
140 #else
141   return file_type::none;
142 #endif
143 }
144 _GLIBCXX_END_NAMESPACE_FILESYSTEM
145 
146 _GLIBCXX_END_NAMESPACE_VERSION
147 } // namespace std
148 
149 #endif // _GLIBCXX_DIR_COMMON_H
150