1 //--------------------------------------------------------------------------
2 // Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
3 //
4 // This program is free software; you can redistribute it and/or modify it
5 // under the terms of the GNU General Public License Version 2 as published
6 // by the Free Software Foundation. You may not use, modify or distribute
7 // this program under any other version of the GNU General Public License.
8 //
9 // This program is distributed in the hope that it will be useful, but
10 // WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License along
15 // with this program; if not, write to the Free Software Foundation, Inc.,
16 // 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 //--------------------------------------------------------------------------
18 // directory.cc author Russ Combs <rucombs@cisco.com>
19
20 #ifdef HAVE_CONFIG_H
21 #include "config.h"
22 #endif
23
24 #include "directory.h"
25
26 #include <fnmatch.h>
27 #include <sys/stat.h>
28
29 #include <cerrno>
30 #include <climits>
31 #include <cstring>
32
Directory(const char * s,const char * f)33 Directory::Directory(const char* s, const char* f)
34 {
35 dir = opendir(s);
36 root = s;
37 len = strlen(s);
38 path = root;
39 sub = nullptr;
40 filter = f ? f : "";
41 error = dir ? 0 : errno;
42 }
43
~Directory()44 Directory::~Directory()
45 {
46 if ( dir )
47 closedir(dir);
48
49 if ( sub )
50 delete sub;
51 }
52
error_on_open()53 int Directory::error_on_open()
54 {
55 return error;
56 }
57
rewind()58 void Directory::rewind()
59 {
60 if ( dir )
61 rewinddir(dir);
62
63 if ( sub )
64 delete sub;
65 }
66
next()67 const char* Directory::next()
68 {
69 if ( sub )
70 {
71 const char* s = sub->next();
72
73 if ( s )
74 return s;
75
76 delete sub;
77 sub = nullptr;
78 }
79
80 struct dirent* de;
81
82 while ( dir && (de = readdir(dir)) )
83 {
84 struct stat sb;
85
86 if ( !strncmp(de->d_name, ".", 1) )
87 continue;
88
89 path.erase(len);
90 path += "/";
91 path += de->d_name;
92
93 if ( path.size() > PATH_MAX - 1 || stat(path.c_str(), &sb) )
94 continue;
95
96 if ( S_ISDIR(sb.st_mode) )
97 {
98 sub = new Directory(path.c_str(), filter.c_str());
99 return next();
100 }
101 else if ( !S_ISREG(sb.st_mode) )
102 {
103 continue;
104 }
105 else if ( !filter.empty() && fnmatch(filter.c_str(), de->d_name, 0) )
106 {
107 continue;
108 }
109 return path.c_str();
110 }
111 return nullptr;
112 }
113
114