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