CernVM-FS  2.9.0
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
pathspec.cc
Go to the documentation of this file.
1 
5 #include "pathspec.h"
6 
7 #include <cassert>
8 
9 #include "logging.h"
10 #include "smalloc.h"
11 
12 Pathspec::Pathspec(const std::string &spec) :
13  regex_compiled_(false),
14  regex_(NULL),
15  relaxed_regex_compiled_(false),
16  relaxed_regex_(NULL),
17  prefix_regex_compiled_(false),
18  prefix_regex_(NULL),
19  glob_string_compiled_(false),
20  glob_string_sequence_compiled_(false),
21  valid_(true),
22  absolute_(false)
23 {
24  Parse(spec);
25  if (patterns_.size() == 0) {
26  valid_ = false;
27  }
28 
29  ElementPatterns::const_iterator i = patterns_.begin();
30  const ElementPatterns::const_iterator iend = patterns_.end();
31  for (; i != iend; ++i) {
32  if (!i->IsValid()) {
33  valid_ = false;
34  }
35  }
36 }
37 
39  patterns_(other.patterns_),
40  regex_compiled_(false), // compiled regex structure cannot be
41  regex_(NULL), // duplicated and needs to be re-compiled
42  relaxed_regex_compiled_(false), // Note: the copy-constructed object will
43  relaxed_regex_(NULL), // perform a lazy evaluation again
44  prefix_regex_compiled_(false),
45  prefix_regex_(NULL),
46  glob_string_compiled_(other.glob_string_compiled_),
47  glob_string_(other.glob_string_),
48  glob_string_sequence_compiled_(other.glob_string_sequence_compiled_),
49  glob_string_sequence_(other.glob_string_sequence_),
50  valid_(other.valid_),
51  absolute_(other.absolute_) {}
52 
55 }
56 
58  if (this != &other) {
59  DestroyRegularExpressions(); // see: copy c'tor for details
60  patterns_ = other.patterns_;
61 
63  glob_string_ = other.glob_string_;
64 
67 
68  valid_ = other.valid_;
69  absolute_ = other.absolute_;
70  }
71 
72  return *this;
73 }
74 
75 
76 void Pathspec::Parse(const std::string &spec) {
77  // parsing is done using std::string iterators to walk through the entire
78  // pathspec parameter. Thus, all parsing methods receive references to these
79  // iterators and increment itr as they pass along.
80  std::string::const_iterator itr = spec.begin();
81  const std::string::const_iterator end = spec.end();
82 
83  absolute_ = (*itr == kSeparator);
84  while (itr != end) {
85  if (*itr == kSeparator) {
86  ++itr;
87  continue;
88  }
89  ParsePathElement(end, &itr);
90  }
91 }
92 
94  const std::string::const_iterator &end,
95  std::string::const_iterator *itr
96 ) {
97  // find the end of the current pattern element (next directory boundary)
98  const std::string::const_iterator begin_element = *itr;
99  while (*itr != end && **itr != kSeparator) {
100  ++(*itr);
101  }
102  const std::string::const_iterator end_element = *itr;
103 
104  // create a PathspecElementPattern out of this directory description
105  patterns_.push_back(PathspecElementPattern(begin_element, end_element));
106 }
107 
108 bool Pathspec::IsMatching(const std::string &query_path) const {
109  assert(IsValid());
110 
111  if (query_path.empty()) {
112  return false;
113  }
114 
115  const bool query_is_absolute = (query_path[0] == kSeparator);
116  return (!query_is_absolute || this->IsAbsolute()) &&
117  IsPathspecMatching(query_path);
118 }
119 
120 bool Pathspec::IsPrefixMatching(const std::string &query_path) const {
121  assert(IsValid());
122  assert(IsAbsolute());
123 
124  if (query_path.empty()) {
125  return false;
126  }
127 
128  const bool query_is_absolute = (query_path[0] == kSeparator);
129  return (query_is_absolute && IsPathspecPrefixMatching(query_path));
130 }
131 
132 bool Pathspec::IsMatchingRelaxed(const std::string &query_path) const {
133  assert(IsValid());
134 
135  if (query_path.empty()) {
136  return false;
137  }
138 
139  return IsPathspecMatchingRelaxed(query_path);
140 }
141 
142 bool Pathspec::IsPathspecMatching(const std::string &query_path) const {
143  return ApplyRegularExpression(query_path, GetRegularExpression());
144 }
145 
146 bool Pathspec::IsPathspecPrefixMatching(const std::string &query_path) const {
148 }
149 
150 bool Pathspec::IsPathspecMatchingRelaxed(const std::string &query_path) const {
152 }
153 
154 bool Pathspec::ApplyRegularExpression(const std::string &query_path,
155  regex_t *regex) const {
156  const char *path = query_path.c_str();
157  const int retval = regexec(regex, path, 0, NULL, 0);
158 
159  if (retval != 0 && retval != REG_NOMATCH) {
161  }
162 
163  return (retval == 0);
164 }
165 
167  if (!regex_compiled_) {
168  const bool is_relaxed = false;
169  const std::string regex = GenerateRegularExpression(is_relaxed);
170  LogCvmfs(kLogPathspec, kLogDebug, "compiled regex: %s", regex.c_str());
171 
173  regex_compiled_ = true;
174  }
175 
176  return regex_;
177 }
178 
180  if (!prefix_regex_compiled_) {
181  const bool is_relaxed = false;
182  const bool is_prefix = true;
183  const std::string regex = GenerateRegularExpression(is_relaxed, is_prefix);
184  LogCvmfs(kLogPathspec, kLogDebug, "compiled regex: %s", regex.c_str());
185 
187  prefix_regex_compiled_ = true;
188  }
189 
190  return prefix_regex_;
191 }
192 
195  const bool is_relaxed = true;
196  const std::string regex = GenerateRegularExpression(is_relaxed);
197  LogCvmfs(kLogPathspec, kLogDebug, "compiled relaxed regex: %s",
198  regex.c_str());
199 
202  }
203 
204  return relaxed_regex_;
205 }
206 
208  const bool is_relaxed,
209  const bool is_prefix) const
210 {
211  // start matching at the first character
212  std::string regex = "^";
213 
214  // absolute paths require a / in the beginning
215  if (IsAbsolute()) {
216  regex += kSeparator;
217  }
218 
219  // concatenate the regular expressions of the compiled path elements
220  ElementPatterns::const_iterator i = patterns_.begin();
221  const ElementPatterns::const_iterator iend = patterns_.end();
222  for (; i != iend; ++i) {
223  regex += i->GenerateRegularExpression(is_relaxed);
224  if (i + 1 != iend) {
225  regex += kSeparator;
226  }
227  }
228 
229  if (is_prefix) {
230  regex += "($|";
231  regex += kSeparator;
232  regex += ".*$)";
233  } else {
234  // a path might end with a trailing slash
235  // (pathspec does not distinguish files and directories)
236  regex += kSeparator;
237  regex += "?$";
238  }
239 
240  return regex;
241 }
242 
243 regex_t* Pathspec::CompileRegularExpression(const std::string &regex) const {
244  regex_t *result = reinterpret_cast<regex_t *>(smalloc(sizeof(regex_t)));
245  const int flags = REG_NOSUB | REG_NEWLINE | REG_EXTENDED;
246  const int retval = regcomp(result, regex.c_str(), flags);
247 
248  if (retval != 0) {
250  assert(false && "failed to compile regex");
251  }
252 
253  return result;
254 }
255 
257  if (regex_compiled_) {
258  assert(regex_ != NULL);
259  regfree(regex_);
260  regex_ = NULL;
261  regex_compiled_ = false;
262  }
263 
265  assert(relaxed_regex_ != NULL);
266  regfree(relaxed_regex_);
267  relaxed_regex_ = NULL;
268  relaxed_regex_compiled_ = false;
269  }
270 }
271 
272 bool Pathspec::operator==(const Pathspec &other) const {
273  if (patterns_.size() != other.patterns_.size() ||
274  IsValid() != other.IsValid() ||
275  IsAbsolute() != other.IsAbsolute()) {
276  return false;
277  }
278 
279  ElementPatterns::const_iterator i = patterns_.begin();
280  const ElementPatterns::const_iterator iend = patterns_.end();
281  ElementPatterns::const_iterator j = other.patterns_.begin();
282  const ElementPatterns::const_iterator jend = other.patterns_.end();
283 
284  for (; i != iend && j != jend; ++i, ++j) {
285  if (*i != *j) {
286  return false;
287  }
288  }
289 
290  return true;
291 }
292 
293 void Pathspec::PrintRegularExpressionError(const int error_code) const {
295  const size_t errbuf_size = 1024;
296  char error[errbuf_size];
297  regerror(error_code, regex_, error, errbuf_size);
298  LogCvmfs(kLogPathspec, kLogStderr, "RegEx Error: %d - %s", error_code, error);
299 }
300 
305  }
306  return glob_string_sequence_;
307 }
308 
309 
311  assert(glob_string_sequence_.empty());
312  ElementPatterns::const_iterator i = patterns_.begin();
313  const ElementPatterns::const_iterator iend = patterns_.end();
314  for (; i != iend; ++i) {
315  const std::string glob_string = i->GenerateGlobString();
316  glob_string_sequence_.push_back(glob_string);
317  }
318 }
319 
320 
321 const std::string& Pathspec::GetGlobString() const {
322  if (!glob_string_compiled_) {
324  glob_string_compiled_ = true;
325  }
326  return glob_string_;
327 }
328 
329 
331  assert(glob_string_.empty());
332 
333  bool is_first = true;
335  GlobStringSequence::const_iterator i = seq.begin();
336  const GlobStringSequence::const_iterator iend = seq.end();
337  for (; i != iend; ++i) {
338  if (!is_first || IsAbsolute()) {
340  }
341  glob_string_ += *i;
342  is_first = false;
343  }
344 }
#define LogCvmfs(source, mask,...)
Definition: logging.h:20
bool glob_string_compiled_
Definition: pathspec.h:178
const GlobStringSequence & GetGlobStringSequence() const
Definition: pathspec.cc:301
bool operator==(const Pathspec &other) const
Definition: pathspec.cc:272
regex_t * relaxed_regex_
Definition: pathspec.h:173
regex_t * GetRelaxedRegularExpression() const
Definition: pathspec.cc:193
regex_t * CompileRegularExpression(const std::string &regex) const
Definition: pathspec.cc:243
assert((mem||(size==0))&&"Out Of Memory")
bool absolute_
Definition: pathspec.h:185
void Parse(const std::string &spec)
Definition: pathspec.cc:76
void ParsePathElement(const std::string::const_iterator &end, std::string::const_iterator *itr)
Definition: pathspec.cc:93
bool IsValid() const
Definition: pathspec.h:106
GlobStringSequence glob_string_sequence_
Definition: pathspec.h:182
bool IsPrefixMatching(const std::string &query_path) const
Definition: pathspec.cc:120
regex_t * GetPrefixRegularExpression() const
Definition: pathspec.cc:179
bool glob_string_sequence_compiled_
Definition: pathspec.h:181
void GenerateGlobString() const
Definition: pathspec.cc:330
std::string GenerateRegularExpression(const bool is_relaxed=false, const bool is_prefix=false) const
Definition: pathspec.cc:207
bool regex_compiled_
Definition: pathspec.h:169
bool valid_
Definition: pathspec.h:184
bool IsPathspecMatchingRelaxed(const std::string &query_path) const
Definition: pathspec.cc:150
bool prefix_regex_compiled_
Definition: pathspec.h:175
bool IsAbsolute() const
Definition: pathspec.h:112
regex_t * GetRegularExpression() const
Definition: pathspec.cc:166
void DestroyRegularExpressions()
Definition: pathspec.cc:256
void PrintRegularExpressionError(const int error_code) const
Definition: pathspec.cc:293
bool IsPathspecPrefixMatching(const std::string &query_path) const
Definition: pathspec.cc:146
static const char kSeparator
Definition: pathspec.h:49
void GenerateGlobStringSequence() const
Definition: pathspec.cc:310
bool IsPathspecMatching(const std::string &query_path) const
Definition: pathspec.cc:142
regex_t * prefix_regex_
Definition: pathspec.h:176
std::vector< std::string > GlobStringSequence
Definition: pathspec.h:58
regex_t * regex_
Definition: pathspec.h:170
bool relaxed_regex_compiled_
Definition: pathspec.h:172
bool ApplyRegularExpression(const std::string &query_path, regex_t *regex) const
Definition: pathspec.cc:154
Pathspec & operator=(const Pathspec &other)
Definition: pathspec.cc:57
bool IsMatchingRelaxed(const std::string &query_path) const
Definition: pathspec.cc:132
const std::string & GetGlobString() const
Definition: pathspec.cc:321
ElementPatterns patterns_
Definition: pathspec.h:167
bool IsMatching(const std::string &query_path) const
Definition: pathspec.cc:108
std::string glob_string_
Definition: pathspec.h:179
~Pathspec()
Definition: pathspec.cc:53
Pathspec(const std::string &spec)
Definition: pathspec.cc:12