| Directory: | cvmfs/ |
|---|---|
| File: | cvmfs/acl.cc |
| Date: | 2026-03-15 02:35:27 |
| Exec | Total | Coverage | |
|---|---|---|---|
| Lines: | 135 | 151 | 89.4% |
| Branches: | 101 | 132 | 76.5% |
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /** | ||
| 2 | * This file is part of the CernVM File System. | ||
| 3 | */ | ||
| 4 | |||
| 5 | #include "acl.h" | ||
| 6 | |||
| 7 | #include <string.h> | ||
| 8 | |||
| 9 | #include <algorithm> | ||
| 10 | #include <cassert> | ||
| 11 | #include <cstring> | ||
| 12 | #include <vector> | ||
| 13 | |||
| 14 | #include "util/posix.h" | ||
| 15 | |||
| 16 | #ifdef __APPLE__ | ||
| 17 | #include <libkern/OSByteOrder.h> | ||
| 18 | #define htole16(x) OSSwapHostToLittleInt16(x) | ||
| 19 | #define htole32(x) OSSwapHostToLittleInt32(x) | ||
| 20 | #endif | ||
| 21 | |||
| 22 | using namespace std; // NOLINT | ||
| 23 | |||
| 24 | #ifdef COMPARE_TO_LIBACL | ||
| 25 | #include "acl/libacl.h" | ||
| 26 | #else // COMPARE_TO_LIBACL | ||
| 27 | |||
| 28 | // ACL permission bits | ||
| 29 | #define ACL_READ (0x04) | ||
| 30 | #define ACL_WRITE (0x02) | ||
| 31 | #define ACL_EXECUTE (0x01) | ||
| 32 | |||
| 33 | // ACL tag types | ||
| 34 | #define ACL_UNDEFINED_TAG (0x00) | ||
| 35 | #define ACL_USER_OBJ (0x01) | ||
| 36 | #define ACL_USER (0x02) | ||
| 37 | #define ACL_GROUP_OBJ (0x04) | ||
| 38 | #define ACL_GROUP (0x08) | ||
| 39 | #define ACL_MASK (0x10) | ||
| 40 | #define ACL_OTHER (0x20) | ||
| 41 | |||
| 42 | // ACL qualifier constants | ||
| 43 | #define ACL_UNDEFINED_ID ((id_t) - 1) | ||
| 44 | |||
| 45 | #endif // COMPARE_TO_LIBACL | ||
| 46 | |||
| 47 | #define ACL_EA_VERSION 0x0002 | ||
| 48 | |||
| 49 | // ACL data structures | ||
| 50 | struct acl_ea_entry { | ||
| 51 | u_int16_t e_tag; | ||
| 52 | u_int16_t e_perm; | ||
| 53 | u_int32_t e_id; | ||
| 54 | |||
| 55 | // implements sorting compatible with libacl | ||
| 56 | 3813 | bool operator<(const acl_ea_entry &other) const { | |
| 57 |
2/2✓ Branch 0 taken 3567 times.
✓ Branch 1 taken 246 times.
|
3813 | if (e_tag != other.e_tag) { |
| 58 | 3567 | return e_tag < other.e_tag; | |
| 59 | } | ||
| 60 | 246 | return e_id < other.e_id; | |
| 61 | } | ||
| 62 | }; | ||
| 63 | |||
| 64 | struct acl_ea_header { | ||
| 65 | u_int32_t a_version; | ||
| 66 | acl_ea_entry a_entries[0]; | ||
| 67 | }; | ||
| 68 | |||
| 69 | 902 | static int acl_from_text_to_string_entries(const string &acl_string, | |
| 70 | vector<string> &string_entries) { | ||
| 71 | 902 | std::size_t entry_pos = 0; | |
| 72 |
2/2✓ Branch 0 taken 3567 times.
✓ Branch 1 taken 574 times.
|
4141 | while (entry_pos != string::npos) { |
| 73 | size_t entry_length; | ||
| 74 | size_t next_pos; | ||
| 75 | 3567 | size_t const sep_pos = acl_string.find_first_of(",\n", entry_pos); | |
| 76 |
2/2✓ Branch 0 taken 902 times.
✓ Branch 1 taken 2665 times.
|
3567 | if (sep_pos == string::npos) { |
| 77 |
2/2✓ Branch 1 taken 574 times.
✓ Branch 2 taken 328 times.
|
902 | if (acl_string.length() > entry_pos) { |
| 78 | 574 | entry_length = acl_string.length() - entry_pos; | |
| 79 | 574 | next_pos = string::npos; | |
| 80 | } else { | ||
| 81 | // we've just looked past a trailing delimiter | ||
| 82 | 328 | break; | |
| 83 | } | ||
| 84 | } else { | ||
| 85 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2665 times.
|
2665 | assert(sep_pos >= entry_pos); |
| 86 | 2665 | entry_length = sep_pos - entry_pos; | |
| 87 | 2665 | next_pos = sep_pos + 1; | |
| 88 | } | ||
| 89 |
2/2✓ Branch 0 taken 451 times.
✓ Branch 1 taken 2788 times.
|
3239 | if (entry_length == 0) { |
| 90 | // libacl tolerates excessive whitespace but not excessive delimiters. | ||
| 91 | // It's simpler for us to treat whitespace as delimiters. | ||
| 92 | 451 | entry_pos = next_pos; | |
| 93 | 451 | continue; | |
| 94 | } | ||
| 95 |
1/2✓ Branch 1 taken 2788 times.
✗ Branch 2 not taken.
|
2788 | string entry(acl_string, entry_pos, entry_length); |
| 96 | 2788 | entry_pos = next_pos; | |
| 97 | |||
| 98 | // search for '#'-starting comment, discard if found | ||
| 99 | 2788 | size_t const comment_pos = entry.find('#'); | |
| 100 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2788 times.
|
2788 | if (comment_pos != string::npos) { |
| 101 | ✗ | entry = string(entry, 0, comment_pos); | |
| 102 | } | ||
| 103 | |||
| 104 | // TODO(autkin): trim whitespace on both ends | ||
| 105 | |||
| 106 | // discard empty lines | ||
| 107 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2788 times.
|
2788 | if (entry.length() == 0) { |
| 108 | ✗ | continue; | |
| 109 | } | ||
| 110 | |||
| 111 |
1/2✓ Branch 1 taken 2788 times.
✗ Branch 2 not taken.
|
2788 | string_entries.push_back(entry); |
| 112 |
1/2✓ Branch 1 taken 2788 times.
✗ Branch 2 not taken.
|
2788 | } |
| 113 | 902 | return 0; | |
| 114 | } | ||
| 115 | |||
| 116 | 2542 | static int acl_parms_from_text(const string &str, u_int16_t *perms) { | |
| 117 | // Currently unsupported syntax features found in setfacl: | ||
| 118 | // - X (capital x) | ||
| 119 | // - numeric syntax | ||
| 120 | // See "man 1 setfacl", "The perms field is..." | ||
| 121 | |||
| 122 | 2542 | *perms = 0; | |
| 123 |
2/2✓ Branch 5 taken 4592 times.
✓ Branch 6 taken 2542 times.
|
7134 | for (const char &c : str) { |
| 124 |
4/5✓ Branch 0 taken 1681 times.
✓ Branch 1 taken 1025 times.
✓ Branch 2 taken 492 times.
✓ Branch 3 taken 1394 times.
✗ Branch 4 not taken.
|
4592 | switch (c) { |
| 125 | 1681 | case 'r': | |
| 126 | 1681 | *perms |= ACL_READ; | |
| 127 | 1681 | break; | |
| 128 | 1025 | case 'w': | |
| 129 | 1025 | *perms |= ACL_WRITE; | |
| 130 | 1025 | break; | |
| 131 | 492 | case 'x': | |
| 132 | 492 | *perms |= ACL_EXECUTE; | |
| 133 | 492 | break; | |
| 134 | 1394 | case '-': | |
| 135 | 1394 | break; | |
| 136 | ✗ | default: | |
| 137 | ✗ | return EINVAL; | |
| 138 | } | ||
| 139 | } | ||
| 140 | 2542 | return 0; | |
| 141 | } | ||
| 142 | |||
| 143 | 2583 | static int acl_entry_from_text(const string &str, acl_ea_entry &entry) { | |
| 144 | // break down to 3 fields by ':' | ||
| 145 | // type:qualifier:permissions according to terminology | ||
| 146 | // e_tag:e_id:e_perm are acl_ea_entry field names | ||
| 147 | 2583 | size_t sep_pos = str.find(':'); | |
| 148 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2583 times.
|
2583 | if (sep_pos == string::npos) { |
| 149 | ✗ | return EINVAL; | |
| 150 | } | ||
| 151 |
1/2✓ Branch 1 taken 2583 times.
✗ Branch 2 not taken.
|
2583 | string const type(str, 0, sep_pos); |
| 152 | 2583 | size_t next_field_pos = sep_pos + 1; | |
| 153 | 2583 | sep_pos = str.find(':', next_field_pos); | |
| 154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2583 times.
|
2583 | if (sep_pos == string::npos) { |
| 155 | ✗ | return EINVAL; | |
| 156 | } | ||
| 157 |
1/2✓ Branch 1 taken 2583 times.
✗ Branch 2 not taken.
|
2583 | string const qualifier(str, next_field_pos, sep_pos - next_field_pos); |
| 158 | 2583 | next_field_pos = sep_pos + 1; | |
| 159 |
1/2✓ Branch 2 taken 2583 times.
✗ Branch 3 not taken.
|
2583 | string const permissions(str, next_field_pos); |
| 160 | |||
| 161 |
6/6✓ Branch 1 taken 2542 times.
✓ Branch 2 taken 41 times.
✓ Branch 4 taken 984 times.
✓ Branch 5 taken 1558 times.
✓ Branch 6 taken 1025 times.
✓ Branch 7 taken 1558 times.
|
2583 | if (!type.compare("user") || !type.compare("u")) { |
| 162 |
2/2✓ Branch 1 taken 615 times.
✓ Branch 2 taken 410 times.
|
1025 | entry.e_tag = qualifier.empty() ? ACL_USER_OBJ : ACL_USER; |
| 163 |
6/6✓ Branch 1 taken 1435 times.
✓ Branch 2 taken 123 times.
✓ Branch 4 taken 615 times.
✓ Branch 5 taken 820 times.
✓ Branch 6 taken 738 times.
✓ Branch 7 taken 820 times.
|
1558 | } else if (!type.compare("group") || !type.compare("g")) { |
| 164 |
2/2✓ Branch 1 taken 574 times.
✓ Branch 2 taken 164 times.
|
738 | entry.e_tag = qualifier.empty() ? ACL_GROUP_OBJ : ACL_GROUP; |
| 165 |
6/6✓ Branch 1 taken 779 times.
✓ Branch 2 taken 41 times.
✓ Branch 4 taken 533 times.
✓ Branch 5 taken 246 times.
✓ Branch 6 taken 574 times.
✓ Branch 7 taken 246 times.
|
820 | } else if (!type.compare("other") || !type.compare("o")) { |
| 166 | 574 | entry.e_tag = ACL_OTHER; | |
| 167 |
6/6✓ Branch 1 taken 123 times.
✓ Branch 2 taken 123 times.
✓ Branch 4 taken 82 times.
✓ Branch 5 taken 41 times.
✓ Branch 6 taken 205 times.
✓ Branch 7 taken 41 times.
|
246 | } else if (!type.compare("mask") || !type.compare("m")) { |
| 168 | 205 | entry.e_tag = ACL_MASK; | |
| 169 | } else { | ||
| 170 | 41 | return EINVAL; | |
| 171 | } | ||
| 172 | 2542 | entry.e_tag = htole16(entry.e_tag); | |
| 173 | |||
| 174 |
2/2✓ Branch 1 taken 1968 times.
✓ Branch 2 taken 574 times.
|
2542 | if (qualifier.empty()) { |
| 175 | 1968 | entry.e_id = ACL_UNDEFINED_ID; | |
| 176 | } else { | ||
| 177 | char *at_null_terminator_if_number; | ||
| 178 | 574 | long number = strtol(qualifier.c_str(), &at_null_terminator_if_number, 10); | |
| 179 |
2/2✓ Branch 0 taken 205 times.
✓ Branch 1 taken 369 times.
|
574 | if (*at_null_terminator_if_number != '\0') { |
| 180 | bool ok; | ||
| 181 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | if (entry.e_tag == htole16(ACL_USER)) { |
| 182 | [[maybe_unused]] gid_t main_gid; | ||
| 183 | uid_t uid; | ||
| 184 |
1/2✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
|
205 | ok = GetUidOf(qualifier, &uid, &main_gid); |
| 185 | 205 | number = uid; | |
| 186 | ✗ | } else if (entry.e_tag == htole16(ACL_GROUP)) { | |
| 187 | gid_t gid; | ||
| 188 | ✗ | ok = GetGidOf(qualifier, &gid); | |
| 189 | ✗ | number = gid; | |
| 190 | } else { | ||
| 191 | ✗ | assert(false); | |
| 192 | } | ||
| 193 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
|
205 | if (!ok) { |
| 194 | ✗ | return EINVAL; | |
| 195 | } | ||
| 196 | } | ||
| 197 | 574 | entry.e_id = htole32(number); | |
| 198 | } | ||
| 199 | |||
| 200 | // parse perms | ||
| 201 | u_int16_t host_byteorder_perms; | ||
| 202 | int ret; | ||
| 203 | 2542 | ret = acl_parms_from_text(permissions, &host_byteorder_perms); | |
| 204 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2542 times.
|
2542 | if (ret) { |
| 205 | ✗ | return ret; | |
| 206 | } | ||
| 207 | 2542 | entry.e_perm = htole16(host_byteorder_perms); | |
| 208 | |||
| 209 | 2542 | return 0; | |
| 210 | 2583 | } | |
| 211 | |||
| 212 | 861 | static bool acl_valid_builtin(const vector<acl_ea_entry> &entries) { | |
| 213 | // From man acl_valid: | ||
| 214 | // The three required entries ACL_USER_OBJ, ACL_GROUP_OBJ, and ACL_OTHER must | ||
| 215 | // exist exactly once in the ACL. | ||
| 216 | // | ||
| 217 | // If the ACL contains any ACL_USER or ACL_GROUP entries, then an ACL_MASK | ||
| 218 | // entry is also required. | ||
| 219 | // | ||
| 220 | // The ACL may contain at most one ACL_MASK entry. | ||
| 221 | // | ||
| 222 | // The user identifiers must be unique among all entries of type ACL_USER. | ||
| 223 | // The group identifiers must be unique among all entries of type ACL_GROUP. | ||
| 224 | |||
| 225 | 861 | bool types_met[ACL_OTHER + 1] = { | |
| 226 | false, | ||
| 227 | }; | ||
| 228 | |||
| 229 |
2/2✓ Branch 4 taken 2378 times.
✓ Branch 5 taken 820 times.
|
3198 | for (auto entry_it = entries.begin(); entry_it != entries.end(); ++entry_it) { |
| 230 | 2378 | const acl_ea_entry &e = *entry_it; | |
| 231 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2378 times.
|
2378 | assert(e.e_tag <= ACL_OTHER); |
| 232 | 2378 | bool &type_met = types_met[e.e_tag]; | |
| 233 |
2/3✓ Branch 0 taken 1886 times.
✓ Branch 1 taken 492 times.
✗ Branch 2 not taken.
|
2378 | switch (e.e_tag) { |
| 234 | // at most one of these types | ||
| 235 | 1886 | case ACL_USER_OBJ: | |
| 236 | case ACL_GROUP_OBJ: | ||
| 237 | case ACL_OTHER: | ||
| 238 | case ACL_MASK: | ||
| 239 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 1845 times.
|
1886 | if (type_met) { |
| 240 | 41 | return false; | |
| 241 | } else { | ||
| 242 | 1845 | type_met = true; | |
| 243 | } | ||
| 244 | 1845 | break; | |
| 245 | 492 | case ACL_USER: | |
| 246 | case ACL_GROUP: | ||
| 247 | 492 | type_met = true; | |
| 248 | 492 | break; | |
| 249 | ✗ | default: | |
| 250 | ✗ | assert(false); | |
| 251 | } | ||
| 252 | } | ||
| 253 |
4/4✓ Branch 0 taken 533 times.
✓ Branch 1 taken 287 times.
✓ Branch 2 taken 492 times.
✓ Branch 3 taken 41 times.
|
820 | if (!(types_met[ACL_USER_OBJ] && types_met[ACL_GROUP_OBJ] |
| 254 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 492 times.
|
492 | && types_met[ACL_OTHER])) { |
| 255 | 328 | return false; | |
| 256 | } | ||
| 257 |
6/6✓ Branch 0 taken 287 times.
✓ Branch 1 taken 205 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 246 times.
✓ Branch 4 taken 41 times.
✓ Branch 5 taken 205 times.
|
492 | if ((types_met[ACL_USER] || types_met[ACL_GROUP]) && !types_met[ACL_MASK]) { |
| 258 | 41 | return false; | |
| 259 | } | ||
| 260 | // TODO(autkin): ACL_USER, ACL_GROUP uniqueness checks. Not a pressing issue. | ||
| 261 | 451 | return true; | |
| 262 | } | ||
| 263 | |||
| 264 | 902 | int acl_from_text_to_xattr_value(const string &textual_acl, char *&o_binary_acl, | |
| 265 | size_t &o_size, bool &o_equiv_mode) { | ||
| 266 | int ret; | ||
| 267 | |||
| 268 | 902 | o_equiv_mode = true; | |
| 269 | |||
| 270 | // get individual textual entries from one big text | ||
| 271 | 902 | vector<string> string_entries; | |
| 272 |
1/2✓ Branch 1 taken 902 times.
✗ Branch 2 not taken.
|
902 | ret = acl_from_text_to_string_entries(textual_acl, string_entries); |
| 273 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 902 times.
|
902 | if (ret) { |
| 274 | ✗ | return ret; | |
| 275 | } | ||
| 276 | |||
| 277 | // get individual entries in structural form | ||
| 278 | 902 | vector<acl_ea_entry> entries; | |
| 279 | 902 | for (auto string_it = string_entries.begin(); | |
| 280 |
2/2✓ Branch 2 taken 2583 times.
✓ Branch 3 taken 861 times.
|
3444 | string_it != string_entries.end(); |
| 281 | 2542 | ++string_it) { | |
| 282 | acl_ea_entry entry; | ||
| 283 |
1/2✓ Branch 2 taken 2583 times.
✗ Branch 3 not taken.
|
2583 | ret = acl_entry_from_text(*string_it, entry); |
| 284 |
2/2✓ Branch 0 taken 41 times.
✓ Branch 1 taken 2542 times.
|
2583 | if (ret) { |
| 285 | 41 | return ret; | |
| 286 | } | ||
| 287 |
4/4✓ Branch 0 taken 2378 times.
✓ Branch 1 taken 164 times.
✓ Branch 2 taken 410 times.
✓ Branch 3 taken 1968 times.
|
2542 | if (entry.e_tag == ACL_GROUP || entry.e_tag == ACL_USER) { |
| 288 | 574 | o_equiv_mode = false; | |
| 289 | } | ||
| 290 |
1/2✓ Branch 1 taken 2542 times.
✗ Branch 2 not taken.
|
2542 | entries.push_back(entry); |
| 291 | } | ||
| 292 | |||
| 293 | // sort entries as libacl does, to be able to use it in testing as a reference | ||
| 294 |
1/2✓ Branch 3 taken 861 times.
✗ Branch 4 not taken.
|
861 | sort(entries.begin(), entries.end()); |
| 295 | |||
| 296 | // reject what acl_valid() rejects, to be able to use it in testing | ||
| 297 |
2/2✓ Branch 1 taken 410 times.
✓ Branch 2 taken 451 times.
|
861 | if (!acl_valid_builtin(entries)) { |
| 298 | 410 | return EINVAL; | |
| 299 | } | ||
| 300 | |||
| 301 | // if nothing but usual u,g,o bits, don't produce a binary. Mimicking libacl. | ||
| 302 |
2/2✓ Branch 0 taken 246 times.
✓ Branch 1 taken 205 times.
|
451 | if (o_equiv_mode) { |
| 303 | 246 | o_binary_acl = NULL; | |
| 304 | 246 | o_size = 0; | |
| 305 | 246 | return 0; | |
| 306 | } | ||
| 307 | |||
| 308 | // get one big buffer with all the entries in the "on-disk" xattr format | ||
| 309 | 205 | size_t const acl_entry_count = entries.size(); | |
| 310 | 205 | size_t const buf_size = sizeof(acl_ea_header) | |
| 311 | 205 | + (acl_entry_count * sizeof(acl_ea_entry)); | |
| 312 | 205 | char *buf = static_cast<char *>(malloc(buf_size)); | |
| 313 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 205 times.
|
205 | if (!buf) { |
| 314 | ✗ | return ENOMEM; | |
| 315 | } | ||
| 316 | 205 | acl_ea_header *header = reinterpret_cast<acl_ea_header *>(buf); | |
| 317 | 205 | header->a_version = htole32(ACL_EA_VERSION); | |
| 318 | 205 | acl_ea_entry *ext_entry = reinterpret_cast<acl_ea_entry *>(header + 1); | |
| 319 |
2/2✓ Branch 3 taken 1189 times.
✓ Branch 4 taken 205 times.
|
1394 | for (auto entry_it = entries.begin(); entry_it != entries.end(); ++entry_it) { |
| 320 | 1189 | *ext_entry = *entry_it; | |
| 321 | 1189 | ext_entry += 1; | |
| 322 | } | ||
| 323 | |||
| 324 | 205 | o_binary_acl = buf; | |
| 325 | 205 | o_size = buf_size; | |
| 326 | 205 | return 0; | |
| 327 | 902 | } | |
| 328 | |||
| 329 | #ifdef COMPARE_TO_LIBACL | ||
| 330 | int acl_from_text_to_xattr_value_libacl(const string textual_acl, | ||
| 331 | char *&o_binary_acl, size_t &o_size, | ||
| 332 | bool &o_equiv_mode) { | ||
| 333 | acl_t acl = acl_from_text( | ||
| 334 | textual_acl.c_str()); // Convert ACL string to acl_t object | ||
| 335 | if (!acl) { | ||
| 336 | return EINVAL; | ||
| 337 | } | ||
| 338 | if (acl_valid(acl) != 0) { | ||
| 339 | acl_free(acl); | ||
| 340 | return EINVAL; | ||
| 341 | } | ||
| 342 | |||
| 343 | // check if the ACL string contains more than the synthetic ACLs | ||
| 344 | int equiv = acl_equiv_mode(acl, NULL); | ||
| 345 | assert(equiv != -1); | ||
| 346 | |||
| 347 | o_equiv_mode = equiv == 0; | ||
| 348 | if (!o_equiv_mode) { | ||
| 349 | o_binary_acl = (char *)acl_to_xattr(acl, &o_size); | ||
| 350 | } else { | ||
| 351 | o_binary_acl = NULL; | ||
| 352 | o_size = 0; | ||
| 353 | } | ||
| 354 | acl_free(acl); | ||
| 355 | return 0; | ||
| 356 | } | ||
| 357 | |||
| 358 | int acl_from_text_to_xattr_value_both_impl(const string textual_acl, | ||
| 359 | char *&o_binary_acl, size_t &o_size, | ||
| 360 | bool &o_equiv_mode) { | ||
| 361 | struct impl_result { | ||
| 362 | int ret; | ||
| 363 | size_t binary_size; | ||
| 364 | char *binary_acl; | ||
| 365 | bool equiv_mode; | ||
| 366 | } b, l; | ||
| 367 | b.ret = acl_from_text_to_xattr_value(textual_acl, b.binary_acl, b.binary_size, | ||
| 368 | b.equiv_mode); | ||
| 369 | l.ret = acl_from_text_to_xattr_value_libacl(textual_acl, l.binary_acl, | ||
| 370 | l.binary_size, l.equiv_mode); | ||
| 371 | assert(b.ret == l.ret); | ||
| 372 | if (!l.ret) { | ||
| 373 | assert(b.binary_size == l.binary_size); | ||
| 374 | assert(0 == memcmp(b.binary_acl, l.binary_acl, b.binary_size)); | ||
| 375 | assert(b.equiv_mode == l.equiv_mode); | ||
| 376 | free(l.binary_acl); | ||
| 377 | } | ||
| 378 | o_binary_acl = b.binary_acl; | ||
| 379 | o_size = b.binary_size; | ||
| 380 | o_equiv_mode = b.equiv_mode; | ||
| 381 | return b.ret; | ||
| 382 | } | ||
| 383 | #endif // COMPARE_TO_LIBACL | ||
| 384 |