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