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