| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/path_filters/dirtab.cc |
| Date: | 2025-11-16 02:35:16 |
| 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 | 812 | Dirtab::Dirtab() : valid_(true) { } | |
| 19 | |||
| 20 | |||
| 21 | 21 | bool Dirtab::Open(const std::string &dirtab_path) { | |
| 22 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 21 times.
|
21 | 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 | 21 | FILE *dirtab_file = fopen(dirtab_path.c_str(), "r"); | |
| 30 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 21 times.
|
21 | 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 | 21 | valid_ = Parse(dirtab_file); | |
| 40 | 21 | fclose(dirtab_file); | |
| 41 | 21 | return valid_; | |
| 42 | } | ||
| 43 | |||
| 44 | 728 | bool Dirtab::Parse(const std::string &dirtab) { | |
| 45 | 728 | valid_ = true; | |
| 46 | 728 | off_t line_offset = 0; | |
| 47 |
2/2✓ Branch 1 taken 3338 times.
✓ Branch 2 taken 728 times.
|
4066 | while (line_offset < static_cast<off_t>(dirtab.size())) { |
| 48 | 6676 | const std::string line = GetLineMem(dirtab.c_str() + line_offset, | |
| 49 |
1/2✓ Branch 3 taken 3338 times.
✗ Branch 4 not taken.
|
3338 | dirtab.size() - line_offset); |
| 50 | 3338 | line_offset += line.size() + 1; // +1 == skipped \n | |
| 51 |
3/4✓ Branch 1 taken 3338 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 86 times.
✓ Branch 4 taken 3252 times.
|
3338 | if (!ParseLine(line)) { |
| 52 | 86 | valid_ = false; | |
| 53 | } | ||
| 54 | 3338 | } | |
| 55 |
4/4✓ Branch 0 taken 642 times.
✓ Branch 1 taken 86 times.
✓ Branch 3 taken 599 times.
✓ Branch 4 taken 43 times.
|
728 | valid_ = valid_ && CheckRuleValidity(); |
| 56 | 728 | return valid_; | |
| 57 | } | ||
| 58 | |||
| 59 | |||
| 60 | 42 | bool Dirtab::Parse(FILE *dirtab_file) { | |
| 61 | 42 | valid_ = true; | |
| 62 | 42 | std::string line; | |
| 63 |
3/4✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 42 times.
|
84 | while (GetLineFile(dirtab_file, &line)) { |
| 64 |
2/4✓ Branch 1 taken 42 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 42 times.
|
42 | if (!ParseLine(line)) { |
| 65 | ✗ | valid_ = false; | |
| 66 | } | ||
| 67 | } | ||
| 68 |
3/6✓ Branch 0 taken 42 times.
✗ Branch 1 not taken.
✓ Branch 3 taken 42 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 42 times.
✗ Branch 6 not taken.
|
42 | valid_ = valid_ && CheckRuleValidity(); |
| 69 | 42 | return valid_; | |
| 70 | 42 | } | |
| 71 | |||
| 72 | |||
| 73 | 3380 | 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 | 3380 | std::string::const_iterator itr = line.begin(); | |
| 78 | 3380 | const std::string::const_iterator iend = line.end(); | |
| 79 | 3380 | bool negation = false; | |
| 80 | |||
| 81 | // parse preamble | ||
| 82 | 3380 | SkipWhitespace(iend, &itr); | |
| 83 |
2/2✓ Branch 1 taken 983 times.
✓ Branch 2 taken 2397 times.
|
3380 | if (*itr == Dirtab::kCommentMarker) { |
| 84 | 983 | return true; | |
| 85 |
2/2✓ Branch 1 taken 984 times.
✓ Branch 2 taken 1413 times.
|
2397 | } else if (*itr == Dirtab::kNegationMarker) { |
| 86 | 984 | negation = true; | |
| 87 | 984 | ++itr; | |
| 88 | 984 | SkipWhitespace(iend, &itr); | |
| 89 | } | ||
| 90 | |||
| 91 | // extract and parse pathspec | ||
| 92 |
2/4✓ Branch 2 taken 2397 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 2397 times.
✗ Branch 6 not taken.
|
4794 | const std::string pathspec_str(Trim(std::string(itr, iend))); |
| 93 |
1/2✓ Branch 1 taken 2397 times.
✗ Branch 2 not taken.
|
2397 | return this->ParsePathspec(pathspec_str, negation); |
| 94 | 2397 | } | |
| 95 | |||
| 96 | 2607 | bool Dirtab::ParsePathspec(const std::string &pathspec_str, bool negation) { | |
| 97 |
2/2✓ Branch 1 taken 430 times.
✓ Branch 2 taken 2177 times.
|
2607 | if (pathspec_str.empty()) { |
| 98 | 430 | return true; | |
| 99 | } | ||
| 100 |
1/2✓ Branch 1 taken 2177 times.
✗ Branch 2 not taken.
|
2177 | 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 2134 times.
✓ Branch 2 taken 43 times.
✓ Branch 3 taken 1193 times.
✓ Branch 4 taken 941 times.
✓ Branch 6 taken 43 times.
✓ Branch 7 taken 1150 times.
✓ Branch 8 taken 86 times.
✓ Branch 9 taken 2091 times.
|
2177 | if (!pathspec.IsValid() || (!negation && !pathspec.IsAbsolute())) { |
| 105 | 86 | return false; | |
| 106 | } | ||
| 107 | |||
| 108 | // create a new dirtab rule | ||
| 109 |
1/2✓ Branch 1 taken 2091 times.
✗ Branch 2 not taken.
|
2091 | const Rule rule(pathspec, negation); |
| 110 |
1/2✓ Branch 1 taken 2091 times.
✗ Branch 2 not taken.
|
2091 | AddRule(rule); |
| 111 | 2091 | return true; | |
| 112 | 2177 | } | |
| 113 | |||
| 114 | |||
| 115 | 2091 | void Dirtab::AddRule(const Rule &rule) { | |
| 116 |
2/2✓ Branch 0 taken 941 times.
✓ Branch 1 taken 1150 times.
|
2091 | if (rule.is_negation) { |
| 117 | 941 | negative_rules_.push_back(rule); | |
| 118 | } else { | ||
| 119 | 1150 | positive_rules_.push_back(rule); | |
| 120 | } | ||
| 121 | 2091 | } | |
| 122 | |||
| 123 | |||
| 124 | 684 | bool Dirtab::CheckRuleValidity() const { | |
| 125 | // check if there are contradicting positive and negative rules | ||
| 126 | 684 | Rules::const_iterator p = positive_rules_.begin(); | |
| 127 | 684 | const Rules::const_iterator pend = positive_rules_.end(); | |
| 128 |
2/2✓ Branch 2 taken 1107 times.
✓ Branch 3 taken 641 times.
|
1748 | for (; p != pend; ++p) { |
| 129 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1107 times.
|
1107 | assert(!p->is_negation); |
| 130 | 1107 | Rules::const_iterator n = negative_rules_.begin(); | |
| 131 | 1107 | const Rules::const_iterator nend = negative_rules_.end(); | |
| 132 |
2/2✓ Branch 2 taken 1727 times.
✓ Branch 3 taken 1064 times.
|
2791 | for (; n != nend; ++n) { |
| 133 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 1727 times.
|
1727 | assert(n->is_negation); |
| 134 |
3/4✓ Branch 3 taken 1727 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 43 times.
✓ Branch 6 taken 1684 times.
|
1727 | if (p->pathspec == n->pathspec) { |
| 135 | 43 | return false; | |
| 136 | } | ||
| 137 | } | ||
| 138 | } | ||
| 139 | |||
| 140 | 641 | return true; | |
| 141 | } | ||
| 142 | |||
| 143 | |||
| 144 | 2491 | bool Dirtab::IsMatching(const std::string &path) const { | |
| 145 | // check if path has a positive match | ||
| 146 | 2491 | bool has_positive_match = false; | |
| 147 | 2491 | Rules::const_iterator p = positive_rules_.begin(); | |
| 148 | 2491 | const Rules::const_iterator pend = positive_rules_.end(); | |
| 149 |
2/2✓ Branch 2 taken 4710 times.
✓ Branch 3 taken 1082 times.
|
5792 | for (; p != pend; ++p) { |
| 150 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 4710 times.
|
4710 | assert(!p->is_negation); |
| 151 |
3/4✓ Branch 2 taken 4710 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1409 times.
✓ Branch 5 taken 3301 times.
|
4710 | if (p->pathspec.IsMatching(path)) { |
| 152 | 1409 | has_positive_match = true; | |
| 153 | 1409 | break; | |
| 154 | } | ||
| 155 | } | ||
| 156 | |||
| 157 |
5/6✓ Branch 0 taken 1409 times.
✓ Branch 1 taken 1082 times.
✓ Branch 3 taken 1409 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 1108 times.
✓ Branch 6 taken 301 times.
|
2491 | return has_positive_match && !IsOpposing(path); |
| 158 | } | ||
| 159 | |||
| 160 | |||
| 161 | 4483 | bool Dirtab::IsOpposing(const std::string &path) const { | |
| 162 | 4483 | Rules::const_iterator n = negative_rules_.begin(); | |
| 163 | 4483 | const Rules::const_iterator nend = negative_rules_.end(); | |
| 164 |
2/2✓ Branch 2 taken 8118 times.
✓ Branch 3 taken 3411 times.
|
11529 | for (; n != nend; ++n) { |
| 165 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 8118 times.
|
8118 | assert(n->is_negation); |
| 166 |
3/4✓ Branch 2 taken 8118 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 1072 times.
✓ Branch 5 taken 7046 times.
|
8118 | if (n->pathspec.IsMatchingRelaxed(path)) { |
| 167 | 1072 | return true; | |
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | 3411 | return false; | |
| 172 | } | ||
| 173 | |||
| 174 | } // namespace catalog | ||
| 175 |