Just a comment, is there already code in the filesystem path evaluation that implements similar functionality? Would it make sense to replace with a call to this?
-Gedare On Sat, Oct 4, 2014 at 1:14 AM, Chris Johns <chr...@rtems.org> wrote: > --- > cpukit/libcsupport/Makefile.am | 2 +- > cpukit/libcsupport/src/realpath.c | 253 > ++++++++++++++++++++++++++++++++++++++ > 2 files changed, 254 insertions(+), 1 deletion(-) > create mode 100644 cpukit/libcsupport/src/realpath.c > > diff --git a/cpukit/libcsupport/Makefile.am b/cpukit/libcsupport/Makefile.am > index d39f8f9..40e0800 100644 > --- a/cpukit/libcsupport/Makefile.am > +++ b/cpukit/libcsupport/Makefile.am > @@ -119,7 +119,7 @@ TERMINAL_IDENTIFICATION_C_FILES += src/ttyname.c > LIBC_GLUE_C_FILES = src/__getpid.c src/__gettod.c src/__times.c \ > src/truncate.c src/access.c src/stat.c src/lstat.c src/pathconf.c \ > src/newlibc_reent.c src/newlibc_init.c src/newlibc_exit.c \ > - src/kill_noposix.c src/utsname.c > + src/kill_noposix.c src/utsname.c src/realpath.c > > BSD_LIBC_C_FILES = src/strlcpy.c src/strlcat.c src/issetugid.c > > diff --git a/cpukit/libcsupport/src/realpath.c > b/cpukit/libcsupport/src/realpath.c > new file mode 100644 > index 0000000..dff0838 > --- /dev/null > +++ b/cpukit/libcsupport/src/realpath.c > @@ -0,0 +1,253 @@ > +/* > + * Copyright (c) 2003 Constantin S. Svintsoff <kos...@iclub.nsu.ru> > + * > + * Redistribution and use in source and binary forms, with or without > + * modification, are permitted provided that the following conditions > + * are met: > + * 1. Redistributions of source code must retain the above copyright > + * notice, this list of conditions and the following disclaimer. > + * 2. Redistributions in binary form must reproduce the above copyright > + * notice, this list of conditions and the following disclaimer in the > + * documentation and/or other materials provided with the distribution. > + * 3. The names of the authors may not be used to endorse or promote > + * products derived from this software without specific prior written > + * permission. > + * > + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND > + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE > + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE > + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE > + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL > + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS > + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) > + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT > + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY > + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#if defined(LIBC_SCCS) && !defined(lint) > +static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94"; > +#endif /* LIBC_SCCS and not lint */ > +#include <sys/cdefs.h> > +__FBSDID("$FreeBSD: release/9.1.0/lib/libc/stdlib/realpath.c 240647 > 2012-09-18 13:03:00Z emaste $"); > + > +#if !defined(__rtems__) > +#include "namespace.h" > +#endif > +#include <sys/param.h> > +#include <sys/stat.h> > + > +#include <errno.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > +#if !defined(__rtems__) > +#include "un-namespace.h" > +#endif > + > +/* > + * Find the real name of path, by removing all ".", ".." and symlink > + * components. Returns (resolved) on success, or (NULL) on failure, > + * in which case the path which caused trouble is left in (resolved). > + */ > +char * > +realpath(const char * __restrict path, char * __restrict resolved) > +{ > + struct stat sb; > + char *p, *q, *s; > + size_t left_len, resolved_len; > + unsigned symlinks; > + int m, slen; > + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; > + > + if (path == NULL) { > + errno = EINVAL; > + return (NULL); > + } > + if (path[0] == '\0') { > + errno = ENOENT; > + return (NULL); > + } > + if (resolved == NULL) { > + resolved = malloc(PATH_MAX); > + if (resolved == NULL) > + return (NULL); > + m = 1; > + } else > + m = 0; > + symlinks = 0; > + if (path[0] == '/') { > + resolved[0] = '/'; > + resolved[1] = '\0'; > + if (path[1] == '\0') > + return (resolved); > + resolved_len = 1; > + left_len = strlcpy(left, path + 1, sizeof(left)); > + } else { > + if (getcwd(resolved, PATH_MAX) == NULL) { > + if (m) > + free(resolved); > + else { > + resolved[0] = '.'; > + resolved[1] = '\0'; > + } > + return (NULL); > + } > + resolved_len = strlen(resolved); > + left_len = strlcpy(left, path, sizeof(left)); > + } > + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { > + if (m) > + free(resolved); > + errno = ENAMETOOLONG; > + return (NULL); > + } > + > + /* > + * Iterate over path components in `left'. > + */ > + while (left_len != 0) { > + /* > + * Extract the next path component and adjust `left' > + * and its length. > + */ > + p = strchr(left, '/'); > + s = p ? p : left + left_len; > + if (s - left >= sizeof(next_token)) { > + if (m) > + free(resolved); > + errno = ENAMETOOLONG; > + return (NULL); > + } > + memcpy(next_token, left, s - left); > + next_token[s - left] = '\0'; > + left_len -= s - left; > + if (p != NULL) > + memmove(left, s + 1, left_len + 1); > + if (resolved[resolved_len - 1] != '/') { > + if (resolved_len + 1 >= PATH_MAX) { > + if (m) > + free(resolved); > + errno = ENAMETOOLONG; > + return (NULL); > + } > + resolved[resolved_len++] = '/'; > + resolved[resolved_len] = '\0'; > + } > + if (next_token[0] == '\0') { > + /* > + * Handle consequential slashes. The path > + * before slash shall point to a directory. > + * > + * Only the trailing slashes are not covered > + * by other checks in the loop, but we verify > + * the prefix for any (rare) "//" or "/\0" > + * occurence to not implement lookahead. > + */ > + if (lstat(resolved, &sb) != 0) { > + if (m) > + free(resolved); > + return (NULL); > + } > + if (!S_ISDIR(sb.st_mode)) { > + if (m) > + free(resolved); > + errno = ENOTDIR; > + return (NULL); > + } > + continue; > + } > + else if (strcmp(next_token, ".") == 0) > + continue; > + else if (strcmp(next_token, "..") == 0) { > + /* > + * Strip the last path component except when we have > + * single "/" > + */ > + if (resolved_len > 1) { > + resolved[resolved_len - 1] = '\0'; > + q = strrchr(resolved, '/') + 1; > + *q = '\0'; > + resolved_len = q - resolved; > + } > + continue; > + } > + > + /* > + * Append the next path component and lstat() it. > + */ > + resolved_len = strlcat(resolved, next_token, PATH_MAX); > + if (resolved_len >= PATH_MAX) { > + if (m) > + free(resolved); > + errno = ENAMETOOLONG; > + return (NULL); > + } > + if (lstat(resolved, &sb) != 0) { > + if (m) > + free(resolved); > + return (NULL); > + } > + if (S_ISLNK(sb.st_mode)) { > + if (symlinks++ > MAXSYMLINKS) { > + if (m) > + free(resolved); > + errno = ELOOP; > + return (NULL); > + } > + slen = readlink(resolved, symlink, sizeof(symlink) - > 1); > + if (slen < 0) { > + if (m) > + free(resolved); > + return (NULL); > + } > + symlink[slen] = '\0'; > + if (symlink[0] == '/') { > + resolved[1] = 0; > + resolved_len = 1; > + } else if (resolved_len > 1) { > + /* Strip the last path component. */ > + resolved[resolved_len - 1] = '\0'; > + q = strrchr(resolved, '/') + 1; > + *q = '\0'; > + resolved_len = q - resolved; > + } > + > + /* > + * If there are any path components left, then > + * append them to symlink. The result is placed > + * in `left'. > + */ > + if (p != NULL) { > + if (symlink[slen - 1] != '/') { > + if (slen + 1 >= sizeof(symlink)) { > + if (m) > + free(resolved); > + errno = ENAMETOOLONG; > + return (NULL); > + } > + symlink[slen] = '/'; > + symlink[slen + 1] = 0; > + } > + left_len = strlcat(symlink, left, > + sizeof(symlink)); > + if (left_len >= sizeof(left)) { > + if (m) > + free(resolved); > + errno = ENAMETOOLONG; > + return (NULL); > + } > + } > + left_len = strlcpy(left, symlink, sizeof(left)); > + } > + } > + > + /* > + * Remove trailing slash except when the resolved pathname > + * is a single "/". > + */ > + if (resolved_len > 1 && resolved[resolved_len - 1] == '/') > + resolved[resolved_len - 1] = '\0'; > + return (resolved); > +} > -- > 1.9.3 (Apple Git-50) > > _______________________________________________ > devel mailing list > devel@rtems.org > http://lists.rtems.org/mailman/listinfo/devel _______________________________________________ devel mailing list devel@rtems.org http://lists.rtems.org/mailman/listinfo/devel