[PATCH 1/2] libcsupport: Add realpath.
Gedare Bloom
gedare at rtems.org
Sat Oct 4 17:12:47 UTC 2014
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 <chrisj at 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 <kostik at 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 at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
More information about the devel
mailing list