GCC Code Coverage Report
Directory: cvmfs/ Exec Total Coverage
File: cvmfs/path_filters/dirtab.cc Lines: 82 89 92.1 %
Date: 2019-02-03 02:48:13 Branches: 53 63 84.1 %

Line Branch Exec Source
1
/**
2
 * This file is part of the CernVM File System.
3
 */
4
5
#include "dirtab.h"
6
7
#include <cassert>
8
#include <cerrno>
9
#include <cstdio>
10
#include <cstdlib>
11
12
#include "logging.h"
13
#include "util/posix.h"
14
#include "util/string.h"
15
16
namespace catalog {
17
18
66
Dirtab::Dirtab() : valid_(true) {}
19
20
21
1
bool Dirtab::Open(const std::string &dirtab_path) {
22
1
  if (!FileExists(dirtab_path)) {
23
    LogCvmfs(kLogCatalog, kLogStderr, "Cannot find dirtab at '%s'",
24
             dirtab_path.c_str());
25
    valid_ = false;
26
    return valid_;
27
  }
28
29
1
  FILE *dirtab_file = fopen(dirtab_path.c_str(), "r");
30
1
  if (dirtab_file == NULL) {
31
    LogCvmfs(kLogCatalog, kLogStderr, "Cannot open dirtab for reading at '%s' "
32
                                      "(errno: %d)",
33
             dirtab_path.c_str(), errno);
34
    valid_ = false;
35
    return valid_;
36
  }
37
38
1
  valid_ = Parse(dirtab_file);
39
1
  fclose(dirtab_file);
40
1
  return valid_;
41
}
42
43
62
bool Dirtab::Parse(const std::string &dirtab) {
44
62
  valid_ = true;
45
62
  off_t line_offset = 0;
46
62
  while (line_offset < static_cast<off_t>(dirtab.size())) {
47
    std::string line = GetLineMem(dirtab.c_str() + line_offset,
48
280
                                  dirtab.size() - line_offset);
49
280
    line_offset += line.size() + 1;  // +1 == skipped \n
50
280
    if (!ParseLine(line)) {
51
8
      valid_ = false;
52
    }
53
  }
54

62
  valid_ = valid_ && CheckRuleValidity();
55
62
  return valid_;
56
}
57
58
59
2
bool Dirtab::Parse(FILE *dirtab_file) {
60
2
  valid_ = true;
61
2
  std::string line;
62
6
  while (GetLineFile(dirtab_file, &line)) {
63
2
    if (!ParseLine(line)) {
64
      valid_ = false;
65
    }
66
  }
67

2
  valid_ = valid_ && CheckRuleValidity();
68
2
  return valid_;
69
}
70
71
72
282
bool Dirtab::ParseLine(const std::string &line) {
73
  // line parsing is done using std::string iterators. Each parsing method ex-
74
  // pects an iterator and the end iterator. While parsing itr is constantly
75
  // incremented to walk through the given .cvmfsdirtab line.
76
282
        std::string::const_iterator itr  = line.begin();
77
282
  const std::string::const_iterator iend = line.end();
78
282
  bool negation = false;
79
80
  // parse preamble
81
282
  SkipWhitespace(iend, &itr);
82
282
  if (*itr == Dirtab::kCommentMarker) {
83
80
    return true;
84
202
  } else if (*itr == Dirtab::kNegationMarker) {
85
82
    negation = true;
86
82
    ++itr;
87
82
    SkipWhitespace(iend, &itr);
88
  }
89
90
  // extract and parse pathspec
91
202
  std::string pathspec_str(Trim(std::string(itr, iend)));
92
202
  return this->ParsePathspec(pathspec_str, negation);
93
}
94
95
212
bool Dirtab::ParsePathspec(const std::string &pathspec_str, bool negation) {
96
212
  if (pathspec_str.empty()) {
97
40
    return true;
98
  }
99
172
  Pathspec pathspec(pathspec_str);
100
101
  // all generated Pathspecs need to be valid and positive rules must be
102
  // absolute. Otherwise the .cvmfsdirtab is not valid.
103


172
  if ( !pathspec.IsValid() ||
104
      (!negation && !pathspec.IsAbsolute())) {
105
8
    return false;
106
  }
107
108
  // create a new dirtab rule
109
164
  const Rule rule(pathspec, negation);
110
164
  AddRule(rule);
111
164
  return true;
112
}
113
114
115
164
void Dirtab::AddRule(const Rule &rule) {
116
164
  if (rule.is_negation) {
117
78
    negative_rules_.push_back(rule);
118
  } else {
119
86
    positive_rules_.push_back(rule);
120
  }
121
164
}
122
123
124
56
bool Dirtab::CheckRuleValidity() const {
125
  // check if there are contradicting positive and negative rules
126
56
        Rules::const_iterator p    = positive_rules_.begin();
127
56
  const Rules::const_iterator pend = positive_rules_.end();
128
134
  for (; p != pend; ++p) {
129
82
    assert(!p->is_negation);
130
82
          Rules::const_iterator n    = negative_rules_.begin();
131
82
    const Rules::const_iterator nend = negative_rules_.end();
132
211
    for (; n != nend; ++n) {
133
133
      assert(n->is_negation);
134
133
      if (p->pathspec == n->pathspec) {
135
4
        return false;
136
      }
137
    }
138
  }
139
140
52
  return true;
141
}
142
143
144
185
bool Dirtab::IsMatching(const std::string &path) const {
145
  // check if path has a positive match
146
185
  bool has_positive_match = false;
147
185
        Rules::const_iterator p    = positive_rules_.begin();
148
185
  const Rules::const_iterator pend = positive_rules_.end();
149
391
  for (; p != pend; ++p) {
150
318
    assert(!p->is_negation);
151
318
    if (p->pathspec.IsMatching(path)) {
152
112
      has_positive_match = true;
153
112
      break;
154
    }
155
  }
156
157

185
  return has_positive_match && !IsOpposing(path);
158
}
159
160
161
315
bool Dirtab::IsOpposing(const std::string &path) const {
162
315
        Rules::const_iterator n    = negative_rules_.begin();
163
315
  const Rules::const_iterator nend = negative_rules_.end();
164
836
  for (; n != nend; ++n) {
165
615
    assert(n->is_negation);
166
615
    if (n->pathspec.IsMatchingRelaxed(path)) {
167
94
      return true;
168
    }
169
  }
170
171
221
  return false;
172
}
173
174
}  // namespace catalog