1 /*
2  * Copyright (c) 2009 - 2011 Miek Gieben
3  * License: GPLv3(+), see LICENSE for details
4  */
5 #include "rdup.h"
6 
7 /*
8  * Remove /./ and /../ and // from a pathname
9  * An absolute pathname argument is required.
10  * Returns NULL on error, otherwise NULL terminated
11  * sanitized pathname.
12  *
13  * Also see realpath(3)
14  */
abspath(char * path)15 char *abspath(char *path)
16 {
17 	char *p, *c;
18 	char *slash, *abspath2;
19 	char *abspath;
20 	int i;
21 
22 	if (!path)
23 		return NULL;
24 
25 	if (!g_path_is_absolute(path))
26 		return NULL;
27 
28 	/* abspath can be NULL or abspath[0] == '\0'. The NULL
29 	 * is initial. the [0] == '\0' is when we got back to
30 	 * the root
31 	 */
32 	abspath = NULL;
33 	abspath2 = g_strdup(path);
34 	i = strlen(abspath2);
35 	if (i > BUFSIZE)
36 		return NULL;
37 
38 	/* add closing / (guard) */
39 	if (abspath2[i - 1] != '/') {
40 		abspath2 = g_realloc(abspath2, i + 2);
41 		abspath2[i] = '/';
42 		abspath2[i + 1] = '\0';
43 	}
44 
45 	/* jump from slash to slash */
46 	for (p = abspath2; (c = strchr(p, '/')); p++) {
47 		*c = '\0';
48 		if (*p == '\0' || (strcmp(p, ".") == 0)) {
49 			/* do nothing */
50 			p = c;
51 		} else if (strcmp(p, "..") == 0) {
52 			/* go back a slash */
53 			if (abspath == NULL || abspath[0] == '\0') {
54 				abspath = g_strdup("/");
55 			} else {
56 				slash = strrchr(abspath, '/');
57 				*slash = '\0';
58 				*c = '/';
59 			}
60 		} else {
61 			if (abspath == NULL || abspath[0] == '\0' ||
62 			    (strcmp(abspath, "/") == 0)) {
63 				g_free(abspath);
64 				abspath = g_strconcat("/", p, NULL);
65 			} else {
66 				gchar *tmp = g_strdup(abspath);
67 				g_free(abspath);
68 				abspath = g_strjoin("/", tmp, p, NULL);
69 				g_free(tmp);
70 			}
71 			*c = '/';
72 		}
73 		p = c;
74 	}
75 	if (abspath == NULL || abspath[0] == '\0')
76 		abspath = g_strdup("/");
77 
78 	g_free(abspath2);
79 	return abspath;
80 }
81