summaryrefslogtreecommitdiff
path: root/src/basic/hash-funcs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/basic/hash-funcs.c')
-rw-r--r--src/basic/hash-funcs.c69
1 files changed, 51 insertions, 18 deletions
diff --git a/src/basic/hash-funcs.c b/src/basic/hash-funcs.c
index c3a4a011b..db48437be 100644
--- a/src/basic/hash-funcs.c
+++ b/src/basic/hash-funcs.c
@@ -1,24 +1,9 @@
-/***
- This file is part of systemd.
+/* SPDX-License-Identifier: LGPL-2.1+ */
- Copyright 2010 Lennart Poettering
- Copyright 2014 Michal Schmidt
-
- systemd is free software; you can redistribute it and/or modify it
- under the terms of the GNU Lesser General Public License as published by
- the Free Software Foundation; either version 2.1 of the License, or
- (at your option) any later version.
-
- systemd is distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- Lesser General Public License for more details.
-
- You should have received a copy of the GNU Lesser General Public License
- along with systemd; If not, see <http://www.gnu.org/licenses/>.
-***/
+#include <string.h>
#include "hash-funcs.h"
+#include "path-util.h"
void string_hash_func(const void *p, struct siphash *state) {
siphash24_compress(p, strlen(p) + 1, state);
@@ -33,6 +18,54 @@ const struct hash_ops string_hash_ops = {
.compare = string_compare_func
};
+void path_hash_func(const void *p, struct siphash *state) {
+ const char *q = p;
+ size_t n;
+
+ 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. */
+
+ n = strspn(q, "/");
+ if (n > 0) { /* Eat up initial slashes, and add one "/" to the hash for all of them */
+ siphash24_compress(q, 1, state);
+ q += n;
+ }
+
+ for (;;) {
+ /* Determine length of next component */
+ n = strcspn(q, "/");
+ if (n == 0) /* Reached the end? */
+ break;
+
+ /* Add this component to the hash and skip over it */
+ siphash24_compress(q, n, state);
+ q += n;
+
+ /* How many slashes follow this component? */
+ n = strspn(q, "/");
+ if (q[n] == 0) /* Is this a trailing slash? If so, we are at the end, and don't care about the slashes anymore */
+ break;
+
+ /* We are not add the end yet. Hash exactly one slash for all of the ones we just encountered. */
+ siphash24_compress(q, 1, state);
+ q += n;
+ }
+}
+
+int path_compare_func(const void *a, const void *b) {
+ return path_compare(a, b);
+}
+
+const struct hash_ops path_hash_ops = {
+ .hash = path_hash_func,
+ .compare = path_compare_func
+};
+
void trivial_hash_func(const void *p, struct siphash *state) {
siphash24_compress(&p, sizeof(p), state);
}