uid-range: optimize to load uid_map file

If uid_map contains many lines, then the previous logic takes O(n^2 log n),
This makes O(n log n).
This commit is contained in:
Yu Watanabe
2022-09-16 20:52:36 +09:00
parent b5739767da
commit f6c13f9f95
2 changed files with 27 additions and 36 deletions
+23 -35
View File
@@ -69,10 +69,7 @@ static void uid_range_coalesce(UidRange **p, size_t *n) {
}
}
int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
bool found = false;
UidRange *x;
int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce) {
assert(p);
assert(n);
@@ -82,37 +79,16 @@ int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
if (start > UINT32_MAX - nr) /* overflow check */
return -ERANGE;
for (size_t i = 0; i < *n; i++) {
x = (*p) + i;
if (uid_range_intersect(x, start, nr)) {
found = true;
break;
}
}
if (!GREEDY_REALLOC(*p, *n + 1))
return -ENOMEM;
if (found) {
uid_t begin, end;
(*p)[(*n)++] = (UidRange) {
.start = start,
.nr = nr,
};
begin = MIN(x->start, start);
end = MAX(x->start + x->nr, start + nr);
x->start = begin;
x->nr = end - begin;
} else {
UidRange *t;
t = reallocarray(*p, *n + 1, sizeof(UidRange));
if (!t)
return -ENOMEM;
*p = t;
x = t + ((*n) ++);
x->start = start;
x->nr = nr;
}
uid_range_coalesce(p, n);
if (coalesce)
uid_range_coalesce(p, n);
return *n;
}
@@ -182,7 +158,9 @@ bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr) {
}
int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
_cleanup_free_ UidRange *q = NULL;
_cleanup_fclose_ FILE *f = NULL;
size_t m = 0;
int r;
/* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
@@ -191,6 +169,9 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
*
* To simplify things this will modify the passed array in case of later failure. */
assert(p);
assert(n);
if (!path)
path = "/proc/self/uid_map";
@@ -214,13 +195,20 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
if (ferror(f))
return errno_or_else(EIO);
return 0;
break;
}
if (k != 3)
return -EBADMSG;
r = uid_range_add(p, n, uid_base, uid_range);
r = uid_range_add_internal(&q, &m, uid_base, uid_range, /* coalesce = */ false);
if (r < 0)
return r;
}
uid_range_coalesce(&q, &m);
*p = TAKE_PTR(q);
*n = m;
return 0;
}
+4 -1
View File
@@ -8,7 +8,10 @@ typedef struct UidRange {
uid_t start, nr;
} UidRange;
int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr);
int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce);
static inline int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
return uid_range_add_internal(p, n, start, nr, true);
}
int uid_range_add_str(UidRange **p, size_t *n, const char *s);
int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);