GCC Code Coverage Report


Directory: cvmfs/
File: cvmfs/path_filters/dirtab.cc
Date: 2026-11-01 02:41:19
Exec Total Coverage
Lines: 87 95 91.6%
Branches: 68 92 73.9%

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 "util/logging.h"
13 #include "util/posix.h"
14 #include "util/string.h"
15
16 namespace catalog {
17
18 2434 Dirtab::Dirtab() : valid_(true) { }
19
20
21 42 bool Dirtab::Open(const std::string &dirtab_path) {
22
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 42 times.
42 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 42 FILE *dirtab_file = fopen(dirtab_path.c_str(), "r");
30
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 42 times.
42 if (dirtab_file == NULL) {
31 ✗ LogCvmfs(kLogCatalog, kLogStderr,
32 "Cannot open dirtab for reading at '%s' "
33 "(errno: %d)",
34 ✗ dirtab_path.c_str(), errno);
35 ✗ valid_ = false;
36 ✗ return valid_;
37 }
38
39 42 valid_ = Parse(dirtab_file);
40 42 fclose(dirtab_file);
41 42 return valid_;
42 }
43
44 1708 bool Dirtab::Parse(const std::string &dirtab) {
45 1708 valid_ = true;
46 1708 off_t line_offset = 0;
47
2/2
✓ Branch 1 taken 5380 times.
✓ Branch 2 taken 1708 times.
7088 while (line_offset < static_cast<off_t>(dirtab.size())) {
48 10760 const std::string line = GetLineMem(dirtab.c_str() + line_offset,
49
1/2
✓ Branch 3 taken 5380 times.
✗ Branch 4 not taken.
5380 dirtab.size() - line_offset);
50 5380 line_offset += line.size() + 1; // +1 == skipped \n
51
3/4
✓ Branch 1 taken 5380 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 52 times.
✓ Branch 4 taken 5328 times.
5380 if (!ParseLine(line)) {
52 52 valid_ = false;
53 }
54 5380 }
55
4/4
✓ Branch 0 taken 1656 times.
✓ Branch 1 taken 52 times.
✓ Branch 3 taken 1630 times.
✓ Branch 4 taken 26 times.
1708 valid_ = valid_ && CheckRuleValidity();
56 1708 return valid_;
57 }
58
59
60 84 bool Dirtab::Parse(FILE *dirtab_file) {
61 84 valid_ = true;
62 84 std::string line;
63
3/4
✓ Branch 1 taken 168 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 84 times.
168 while (GetLineFile(dirtab_file, &line)) {
64
2/4
✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 84 times.
84 if (!ParseLine(line)) {
65 ✗ valid_ = false;
66 }
67 }
68
3/6
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 84 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 84 times.
✗ Branch 6 not taken.
84 valid_ = valid_ && CheckRuleValidity();
69 84 return valid_;
70 84 }
71
72
73 5464 bool Dirtab::ParseLine(const std::string &line) {
74 // line parsing is done using std::string iterators. Each parsing method ex-
75 // pects an iterator and the end iterator. While parsing itr is constantly
76 // incremented to walk through the given .cvmfsdirtab line.
77 5464 std::string::const_iterator itr = line.begin();
78 5464 const std::string::const_iterator iend = line.end();
79 5464 bool negation = false;
80
81 // parse preamble
82 5464 SkipWhitespace(iend, &itr);
83
2/2
✓ Branch 1 taken 946 times.
✓ Branch 2 taken 4518 times.
5464 if (*itr == Dirtab::kCommentMarker) {
84 946 return true;
85
2/2
✓ Branch 1 taken 1128 times.
✓ Branch 2 taken 3390 times.
4518 } else if (*itr == Dirtab::kNegationMarker) {
86 1128 negation = true;
87 1128 ++itr;
88 1128 SkipWhitespace(iend, &itr);
89 }
90
91 // extract and parse pathspec
92
2/4
✓ Branch 2 taken 4518 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4518 times.
✗ Branch 6 not taken.
9036 const std::string pathspec_str(Trim(std::string(itr, iend)));
93
1/2
✓ Branch 1 taken 4518 times.
✗ Branch 2 not taken.
4518 return this->ParsePathspec(pathspec_str, negation);
94 4518 }
95
96 5155 bool Dirtab::ParsePathspec(const std::string &pathspec_str, bool negation) {
97
2/2
✓ Branch 1 taken 806 times.
✓ Branch 2 taken 4349 times.
5155 if (pathspec_str.empty()) {
98 806 return true;
99 }
100
1/2
✓ Branch 1 taken 4349 times.
✗ Branch 2 not taken.
4349 const Pathspec pathspec(pathspec_str);
101
102 // all generated Pathspecs need to be valid and positive rules must be
103 // absolute. Otherwise the .cvmfsdirtab is not valid.
104
8/8
✓ Branch 1 taken 4323 times.
✓ Branch 2 taken 26 times.
✓ Branch 3 taken 3221 times.
✓ Branch 4 taken 1102 times.
✓ Branch 6 taken 26 times.
✓ Branch 7 taken 3195 times.
✓ Branch 8 taken 52 times.
✓ Branch 9 taken 4297 times.
4349 if (!pathspec.IsValid() || (!negation && !pathspec.IsAbsolute())) {
105 52 return false;
106 }
107
108 // create a new dirtab rule
109
1/2
✓ Branch 1 taken 4297 times.
✗ Branch 2 not taken.
4297 const Rule rule(pathspec, negation);
110
1/2
✓ Branch 1 taken 4297 times.
✗ Branch 2 not taken.
4297 AddRule(rule);
111 4297 return true;
112 4349 }
113
114
115 4297 void Dirtab::AddRule(const Rule &rule) {
116
2/2
✓ Branch 0 taken 1102 times.
✓ Branch 1 taken 3195 times.
4297 if (rule.is_negation) {
117 1102 negative_rules_.push_back(rule);
118 } else {
119 3195 positive_rules_.push_back(rule);
120 }
121 4297 }
122
123
124 1740 bool Dirtab::CheckRuleValidity() const {
125 // check if there are contradicting positive and negative rules
126 1740 Rules::const_iterator p = positive_rules_.begin();
127 1740 const Rules::const_iterator pend = positive_rules_.end();
128
2/2
✓ Branch 2 taken 3169 times.
✓ Branch 3 taken 1714 times.
4883 for (; p != pend; ++p) {
129
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 3169 times.
3169 assert(!p->is_negation);
130 3169 Rules::const_iterator n = negative_rules_.begin();
131 3169 const Rules::const_iterator nend = negative_rules_.end();
132
2/2
✓ Branch 2 taken 2285 times.
✓ Branch 3 taken 3143 times.
5428 for (; n != nend; ++n) {
133
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 2285 times.
2285 assert(n->is_negation);
134
3/4
✓ Branch 3 taken 2285 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 26 times.
✓ Branch 6 taken 2259 times.
2285 if (p->pathspec == n->pathspec) {
135 26 return false;
136 }
137 }
138 }
139
140 1714 return true;
141 }
142
143
144 15613 bool Dirtab::IsMatching(const std::string &path) const {
145 // check if path has a positive match
146 15613 bool has_positive_match = false;
147 15613 Rules::const_iterator p = positive_rules_.begin();
148 15613 const Rules::const_iterator pend = positive_rules_.end();
149
2/2
✓ Branch 2 taken 24244 times.
✓ Branch 3 taken 9910 times.
34154 for (; p != pend; ++p) {
150
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 24244 times.
24244 assert(!p->is_negation);
151
3/4
✓ Branch 2 taken 24244 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 5703 times.
✓ Branch 5 taken 18541 times.
24244 if (p->pathspec.IsMatching(path)) {
152 5703 has_positive_match = true;
153 5703 break;
154 }
155 }
156
157
5/6
✓ Branch 0 taken 5703 times.
✓ Branch 1 taken 9910 times.
✓ Branch 3 taken 5703 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 5521 times.
✓ Branch 6 taken 182 times.
15613 return has_positive_match && !IsOpposing(path);
158 }
159
160
161 29455 bool Dirtab::IsOpposing(const std::string &path) const {
162 29455 Rules::const_iterator n = negative_rules_.begin();
163 29455 const Rules::const_iterator nend = negative_rules_.end();
164
2/2
✓ Branch 2 taken 15857 times.
✓ Branch 3 taken 28213 times.
44070 for (; n != nend; ++n) {
165
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 15857 times.
15857 assert(n->is_negation);
166
3/4
✓ Branch 2 taken 15857 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1242 times.
✓ Branch 5 taken 14615 times.
15857 if (n->pathspec.IsMatchingRelaxed(path)) {
167 1242 return true;
168 }
169 }
170
171 28213 return false;
172 }
173
174 } // namespace catalog
175