aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-06-19 15:59:12 +0200
committerDavid Oberhollenzer <david.oberhollenzer@sigma-star.at>2019-06-20 10:26:39 +0200
commitf2981c2ff581e4e425c7b23da43aee29f25232c5 (patch)
tree5e809b9d7aff2db64edcd89afdf1ed4b40f054d5
parent2f172ede7115d0a2730a3b689131042ba559e272 (diff)
simplify and improve canonicalize_name
- Replace scan and memmove with simple automaton - Convert forward to back slashes, lots of file systems treat them equivalenty, this saves us a few more checks down the road - Remove './' path components. We can saveley remove them in a string processing step instead of throwing an error. Also they actually appear often in tar balls, possibly not under user control. Signed-off-by: David Oberhollenzer <david.oberhollenzer@sigma-star.at>
-rw-r--r--include/util.h6
-rw-r--r--lib/util/canonicalize_name.c78
2 files changed, 41 insertions, 43 deletions
diff --git a/include/util.h b/include/util.h
index 28d21bc..d5b20dd 100644
--- a/include/util.h
+++ b/include/util.h
@@ -6,9 +6,9 @@
#include <stdint.h>
/*
- Removes all preceeding and trailing slashes, shortens all sequences of
- slashes to a single slash and returns failure state if one of the path
- components is '..' or '.'.
+ Convert back to forward slashed, remove all preceeding and trailing slashes,
+ collapse all sequences of slashes, remove all path components that are '.'
+ and returns failure state if one of the path components is '..'.
Returns 0 on success.
*/
diff --git a/lib/util/canonicalize_name.c b/lib/util/canonicalize_name.c
index 6703b66..57e4d66 100644
--- a/lib/util/canonicalize_name.c
+++ b/lib/util/canonicalize_name.c
@@ -1,56 +1,54 @@
/* SPDX-License-Identifier: GPL-3.0-or-later */
-#include <string.h>
-
#include "util.h"
-int canonicalize_name(char *filename)
+static void normalize_slashes(char *filename)
{
- char *ptr = filename;
- int i;
-
- while (*ptr == '/')
- ++ptr;
-
- if (ptr != filename) {
- memmove(filename, ptr, strlen(ptr) + 1);
- ptr = filename;
- }
-
- while (*ptr != '\0') {
- if (*ptr == '/') {
- for (i = 0; ptr[i] == '/'; ++i)
- ;
-
- if (i > 1)
- memmove(ptr + 1, ptr + i, strlen(ptr + i) + 1);
- }
-
- if (ptr[0] == '/' && ptr[1] == '\0') {
- *ptr = '\0';
- break;
+ char *dst = filename, *src = filename;
+
+ while (*src == '/' || *src == '\\')
+ ++src;
+
+ while (*src != '\0') {
+ if (*src == '/' || *src == '\\') {
+ while (*src == '/' || *src == '\\')
+ ++src;
+ if (*src == '\0')
+ break;
+ *(dst++) = '/';
+ } else {
+ *(dst++) = *(src++);
}
-
- ++ptr;
}
- ptr = filename;
+ *dst = '\0';
+}
- while (*ptr != '\0') {
- if (ptr[0] == '.') {
- if (ptr[1] == '/' || ptr[1] == '\0')
- return -1;
+int canonicalize_name(char *filename)
+{
+ char *dst = filename, *src = filename;
- if (ptr[1] == '.' &&
- (ptr[2] == '/' || ptr[2] == '\0')) {
- return -1;
+ normalize_slashes(filename);
+
+ while (*src != '\0') {
+ if (src[0] == '.') {
+ if (src[1] == '\0')
+ break;
+ if (src[1] == '/') {
+ src += 2;
+ continue;
}
+ if (src[1] == '.' && (src[2] == '/' || src[2] == '\0'))
+ return -1;
}
- while (*ptr != '\0' && *ptr != '/')
- ++ptr;
- if (*ptr == '/')
- ++ptr;
+ while (*src != '\0' && *src != '/')
+ *(dst++) = *(src++);
+
+ if (*src == '/')
+ *(dst++) = *(src++);
}
+ *dst = '\0';
+ normalize_slashes(filename);
return 0;
}