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