1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <string.h>
4
5 #include "hash-funcs.h"
6 #include "path-util.h"
7
string_hash_func(const char * p,struct siphash * state)8 void string_hash_func(const char *p, struct siphash *state) {
9 siphash24_compress(p, strlen(p) + 1, state);
10 }
11
12 DEFINE_HASH_OPS(string_hash_ops, char, string_hash_func, string_compare_func);
13 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(string_hash_ops_free,
14 char, string_hash_func, string_compare_func, free);
15 DEFINE_HASH_OPS_FULL(string_hash_ops_free_free,
16 char, string_hash_func, string_compare_func, free,
17 void, free);
18
path_hash_func(const char * q,struct siphash * state)19 void path_hash_func(const char *q, struct siphash *state) {
20 bool add_slash = false;
21
22 assert(q);
23 assert(state);
24
25 /* Calculates a hash for a path in a way this duplicate inner slashes don't make a differences, and also
26 * whether there's a trailing slash or not. This fits well with the semantics of path_compare(), which does
27 * similar checks and also doesn't care for trailing slashes. Note that relative and absolute paths (i.e. those
28 * which begin in a slash or not) will hash differently though. */
29
30 /* if path is absolute, add one "/" to the hash. */
31 if (path_is_absolute(q))
32 siphash24_compress("/", 1, state);
33
34 for (;;) {
35 const char *e;
36 int r;
37
38 r = path_find_first_component(&q, true, &e);
39 if (r == 0)
40 return;
41
42 if (add_slash)
43 siphash24_compress_byte('/', state);
44
45 if (r < 0) {
46 /* if a component is invalid, then add remaining part as a string. */
47 string_hash_func(q, state);
48 return;
49 }
50
51 /* Add this component to the hash. */
52 siphash24_compress(e, r, state);
53
54 add_slash = true;
55 }
56 }
57
58 DEFINE_HASH_OPS(path_hash_ops, char, path_hash_func, path_compare);
59 DEFINE_HASH_OPS_WITH_KEY_DESTRUCTOR(path_hash_ops_free,
60 char, path_hash_func, path_compare, free);
61 DEFINE_HASH_OPS_FULL(path_hash_ops_free_free,
62 char, path_hash_func, path_compare, free,
63 void, free);
64
trivial_hash_func(const void * p,struct siphash * state)65 void trivial_hash_func(const void *p, struct siphash *state) {
66 siphash24_compress(&p, sizeof(p), state);
67 }
68
trivial_compare_func(const void * a,const void * b)69 int trivial_compare_func(const void *a, const void *b) {
70 return CMP(a, b);
71 }
72
73 const struct hash_ops trivial_hash_ops = {
74 .hash = trivial_hash_func,
75 .compare = trivial_compare_func,
76 };
77
78 const struct hash_ops trivial_hash_ops_free = {
79 .hash = trivial_hash_func,
80 .compare = trivial_compare_func,
81 .free_key = free,
82 };
83
84 const struct hash_ops trivial_hash_ops_free_free = {
85 .hash = trivial_hash_func,
86 .compare = trivial_compare_func,
87 .free_key = free,
88 .free_value = free,
89 };
90
uint64_hash_func(const uint64_t * p,struct siphash * state)91 void uint64_hash_func(const uint64_t *p, struct siphash *state) {
92 siphash24_compress(p, sizeof(uint64_t), state);
93 }
94
uint64_compare_func(const uint64_t * a,const uint64_t * b)95 int uint64_compare_func(const uint64_t *a, const uint64_t *b) {
96 return CMP(*a, *b);
97 }
98
99 DEFINE_HASH_OPS(uint64_hash_ops, uint64_t, uint64_hash_func, uint64_compare_func);
100
101 #if SIZEOF_DEV_T != 8
devt_hash_func(const dev_t * p,struct siphash * state)102 void devt_hash_func(const dev_t *p, struct siphash *state) {
103 siphash24_compress(p, sizeof(dev_t), state);
104 }
105 #endif
106
devt_compare_func(const dev_t * a,const dev_t * b)107 int devt_compare_func(const dev_t *a, const dev_t *b) {
108 int r;
109
110 r = CMP(major(*a), major(*b));
111 if (r != 0)
112 return r;
113
114 return CMP(minor(*a), minor(*b));
115 }
116
117 DEFINE_HASH_OPS(devt_hash_ops, dev_t, devt_hash_func, devt_compare_func);
118