[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