From f8723eb8c741a02dab3e7cc2096e989c27cb3425 Mon Sep 17 00:00:00 2001 From: Jose Marcial Vieira Bisneto Date: Wed, 7 Dec 2016 09:17:15 -0300 Subject: [PATCH] path: implemented ipfs_path_clean_path --- include/ipfs/path/path.h | 1 + path/path.c | 74 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 75 insertions(+) diff --git a/include/ipfs/path/path.h b/include/ipfs/path/path.h index 0a1541f..9ad58f4 100644 --- a/include/ipfs/path/path.h +++ b/include/ipfs/path/path.h @@ -29,6 +29,7 @@ char** ipfs_path_split_segments (char *p); int ipfs_path_segments_length (char **s); void ipfs_path_free_segments (char ***s); + char *ipfs_path_clean_path(char *str); int ipfs_path_is_just_a_key (char *p); int ipfs_path_pop_last_segment (char **str, char *p); char *ipfs_path_from_segments(char *prefix, char **seg); diff --git a/path/path.c b/path/path.c index 286089f..88c6556 100644 --- a/path/path.c +++ b/path/path.c @@ -91,6 +91,80 @@ void ipfs_path_free_segments (char ***s) } } +// ipfs_path_clean_path returns the shortest path name equivalent to path +// by purely lexical processing. It applies the following rules +// iteratively until no further processing can be done: +// +// 1. Replace multiple slashes with a single slash. +// 2. Eliminate each . path name element (the current directory). +// 3. Eliminate each inner .. path name element (the parent directory) +// along with the non-.. element that precedes it. +// 4. Eliminate .. elements that begin a rooted path: +// that is, replace "/.." by "/" at the beginning of a path. +// +// The returned path ends in a slash only if it is the root "/". +// +// If the result of this process is an empty string, Clean +// returns the string ".". +// +// See also Rob Pike, ``Lexical File Names in Plan 9 or +// Getting Dot-Dot Right,'' +// https://9p.io/sys/doc/lexnames.html +char *ipfs_path_clean_path(char *str) +{ + char *buf; + char **path, **p, *r, *s; + int l; + + l = strlen(str)+3; + r = buf = malloc(l); + *r = '\0'; + if (!r) { + return NULL; + } + buf[--l] = '\0'; + + path = ipfs_path_split_n(str, "/", -1); + if (!path) { + free(r); + return NULL; + } + p = path; + + for (p = path; *p ; p++) { + if (**p == '\0' && r[0] == '\0') { + strncpy(r, "/", l); + } else { + if (strcmp(*p, "..") == 0) { + s = strrchr(r, '/'); + if (s && s > r) { + *s = '\0'; + } + } else if (**p != '\0' && **p != '/' && strcmp(*p, ".")) { + if (*r == '\0') { + strncat(r, "./", l - strlen(r)); + } else if (r[strlen(r)-1] != '/') { + strncat(r, "/", l - strlen(r)); + } + strncat(r, *p, l - strlen(r)); + } + } + } + + ipfs_path_free_segments(&path); + + l = strlen(buf)+1; + r = malloc(l); + if (!r) { + free(buf); + return NULL; + } + strncpy(r, buf, l); + free(buf); + + return r; +} + // ipfs_path_is_just_a_key returns true if the path is of the form or /ipfs/. int ipfs_path_is_just_a_key (char *p) {