Files
systemd/src/basic/hash-funcs.c
Lennart Poettering 1748853700 hash-funcs: tweak odering in devt_compare_func()
Let's order dev_t's by their major first, minor secondary. The binary
encoding of the two fields is weirdly interleaved and different in
kernel and glibc, hence let's focus on the generic part that works like
users would expect it.

So far the function is only used to compare for equality, not for
sorting, hence this has no immediate effect.
2022-04-04 17:04:14 +02:00

118 lines
3.6 KiB
C

/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <string.h>
#include "hash-funcs.h"
#include "path-util.h"
void string_hash_func(const char *p, struct siphash *state) {
siphash24_compress(p, strlen(p) + 1, state);
}
DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
char, string_hash_func, string_compare_func, free);
DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
char, string_hash_func, string_compare_func, free,
void, free);
void path_hash_func(const char *q, struct siphash *state) {
bool add_slash = false;
assert(q);
assert(state);
/* Calculates a hash for a path in a way this duplicate inner slashes don't make a differences, and also
* whether there's a trailing slash or not. This fits well with the semantics of path_compare(), which does
* similar checks and also doesn't care for trailing slashes. Note that relative and absolute paths (i.e. those
* which begin in a slash or not) will hash differently though. */
/* if path is absolute, add one "/" to the hash. */
if (path_is_absolute(q))
siphash24_compress("/", 1, state);
for (;;) {
const char *e;
int r;
r = path_find_first_component(&q, true, &e);
if (r == 0)
return;
if (add_slash)
siphash24_compress_byte('/', state);
if (r < 0) {
/* if a component is invalid, then add remaining part as a string. */
string_hash_func(q, state);
return;
}
/* Add this component to the hash. */
siphash24_compress(e, r, state);
add_slash = true;
}
}
DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare);
DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(path_hash_ops_free,
char, path_hash_func, path_compare, free);
DEFINE_HASH_OPS_FULL(path_hash_ops_free_free,
char, path_hash_func, path_compare, free,
void, free);
void trivial_hash_func(const void *p, struct siphash *state) {
siphash24_compress(&p, sizeof(p), state);
}
int trivial_compare_func(const void *a, const void *b) {
return CMP(a, b);
}
const struct hash_ops trivial_hash_ops = {
.hash = trivial_hash_func,
.compare = trivial_compare_func,
};
const struct hash_ops trivial_hash_ops_free = {
.hash = trivial_hash_func,
.compare = trivial_compare_func,
.free_key = free,
};
const struct hash_ops trivial_hash_ops_free_free = {
.hash = trivial_hash_func,
.compare = trivial_compare_func,
.free_key = free,
.free_value = free,
};
void uint64_hash_func(const uint64_t *p, struct siphash *state) {
siphash24_compress(p, sizeof(uint64_t), state);
}
int uint64_compare_func(const uint64_t *a, const uint64_t *b) {
return CMP(*a, *b);
}
DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func);
#if SIZEOF_DEV_T != 8
void devt_hash_func(const dev_t *p, struct siphash *state) {
siphash24_compress(p, sizeof(dev_t), state);
}
#endif
int devt_compare_func(const dev_t *a, const dev_t *b) {
int r;
r = CMP(major(*a), major(*b));
if (r != 0)
return r;
return CMP(minor(*a), minor(*b));
}
DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);