From 3b23cf388ef088bea1408aeab1eb6b5e3602086a Mon Sep 17 00:00:00 2001 From: pcpa Date: Thu, 24 May 2012 14:40:35 -0300 Subject: [PATCH 1/4] Update fallback implementation of missing libc functions This commit updates realpath.c from http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/realpath.c?rev=1.14;content-type=text/plain and lisp/env.c from http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/getenv.c?rev=1.10;content-type=text/plain and http://www.openbsd.org/cgi-bin/cvsweb/src/lib/libc/stdlib/setenv.c?rev=1.13;content-type=text/plain The update reason is to replace files under "4 clause BSD", that is considered problematic or require special documentation notation or conditions when redistributing free software. Signed-off-by: pcpa --- AUTHORS | 2 +- COPYING | 50 +++++++--- Makefile.am | 3 +- lisp/env.c | 151 ---------------------------- lisp/getenv.c | 81 +++++++++++++++ lisp/setenv.c | 178 +++++++++++++++++++++++++++++++++ realpath.c | 306 +++++++++++++++++++++++++++++---------------------------- 7 files changed, 451 insertions(+), 320 deletions(-) delete mode 100644 lisp/env.c create mode 100644 lisp/getenv.c create mode 100644 lisp/setenv.c diff --git a/AUTHORS b/AUTHORS index 65e5b4c..60c1d32 100644 --- a/AUTHORS +++ b/AUTHORS @@ -135,7 +135,7 @@ Files required for systems that don't have the required calls in the standard libraries: (Based on Copyright notice) -Jan-Simon Pendry +Constantin S. Svintsoff realpath.c (No author information, using CVS tag) diff --git a/COPYING b/COPYING index 4e83706..a2c9fab 100644 --- a/COPYING +++ b/COPYING @@ -1,6 +1,35 @@ +Copyright (c) 2003 Constantin S. Svintsoff + +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. + + + + Copyright (c) 1987, 1993 - The Regents of the University of California. All rights reserved. + The Regents of the University of California. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -10,11 +39,7 @@ are met: 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by the University of - California, Berkeley and its contributors. -4. Neither the name of the University nor the names of its contributors +3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. @@ -34,11 +59,8 @@ SUCH DAMAGE. -Copyright (c) 1994 - The Regents of the University of California. All rights reserved. - -This code is derived from software contributed to Berkeley by -Jan-Simon Pendry. +Copyright (c) 1987 Regents of the University of California. +All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions @@ -48,11 +70,7 @@ are met: 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. All advertising materials mentioning features or use of this software - must display the following acknowledgement: - This product includes software developed by the University of - California, Berkeley and its contributors. -4. Neither the name of the University nor the names of its contributors +3. Neither the name of the University nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. diff --git a/Makefile.am b/Makefile.am index fc7a74c..16a01d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -85,7 +85,8 @@ liblisp_a_SOURCES = \ lisp/xedit.h if NEED_UNSETENV -liblisp_a_SOURCES += lisp/env.c +liblisp_a_SOURCES += lisp/getenv.c +liblisp_a_SOURCES += lisp/setenv.c endif # diff --git a/lisp/env.c b/lisp/env.c deleted file mode 100644 index e87793a..0000000 --- a/lisp/env.c +++ /dev/null @@ -1,151 +0,0 @@ -/* - * Provide setenv() and unsetenv() on platforms that don't have them. - * From FreeBSD's libc. - */ - -/* - * Copyright (c) 1987, 1993 - * The Regents of the University of California. All rights reserved. - * - * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. - */ - -/* $XFree86$ */ - - -#include -#include -#include - -extern char **environ; - -extern int setenv(const char *name, const char *value, int overwrite); -extern void unsetenv(const char *name); - -static char * -findenv(const char *name, int *offset) -{ - int len, i; - const char *np; - char **p, *cp; - - if (name == NULL || environ == NULL) - return NULL; - - for (np = name; *np && *np != '='; ++np) - continue; - len = np - name; - for (p = environ; (cp = *p) != NULL; ++p) { - for (np = name, i = len; i && *cp; i--) - if (*cp++ != *np++) - break; - if (i == 0 && *cp++ == '=') { - *offset = p - environ; - return cp; - } - } - return NULL; -} - -/* - * setenv -- - * Set the value of the environmental variable "name" to be - * "value". If overwrite is set, replace any current value. - */ - -int -setenv(const char *name, const char *value, int overwrite) -{ - static char **alloced; /* if allocated space before */ - char *c; - int l_value, offset; - - if (*value == '=') /* no '=' in value */ - ++value; - l_value = strlen(value); - if ((c = findenv(name, &offset))) { /* find if already exists */ - if (!overwrite) - return 0; - if (strlen(c) >= l_value) { /* old larger; copy over */ - while ((*c++ = *value++)) - ; - return 0; - } - } else { /* create new slot */ - int cnt; - char **p; - - for (p = environ, cnt = 0; *p; ++p, ++cnt) - ; - if (alloced == environ) { /* just increase size */ - p = (char **)realloc((char *)environ, - sizeof(char *) * (cnt + 2)); - if (!p) - return -1; - alloced = environ = p; - } else { /* get new space */ - /* copy old entries into it */ - p = malloc(sizeof(char *) * (cnt + 2)); - if (!p) - return -1; - memcpy(p, environ, cnt * sizeof(char *)); - alloced = environ = p; - } - environ[cnt + 1] = NULL; - offset = cnt; - } - for (c = (char *)name; *c && *c != '='; ++c) /* no '=' in name */ - ; - if (!(environ[offset] = /* name + '=' + value */ - malloc((int)(c - name) + l_value + 2))) - return -1; - for (c = environ[offset]; (*c = *name++) && *c != '='; ++c) - ; - for (*c++ = '='; (*c++ = *value++); ) - ; - return 0; -} - -/* - * unsetenv(name) -- - * Delete environmental variable "name". - */ - -void -unsetenv(const char *name) -{ - char **p; - int offset; - - while (findenv(name, &offset)) /* if set multiple times */ - for (p = &environ[offset];; ++p) - if (!(*p = *(p + 1))) - break; -} - diff --git a/lisp/getenv.c b/lisp/getenv.c new file mode 100644 index 0000000..fd8482e --- /dev/null +++ b/lisp/getenv.c @@ -0,0 +1,81 @@ +/* $OpenBSD: getenv.c,v 1.10 2010/08/23 22:31:50 millert Exp $ */ +/* + * Copyright (c) 1987, 1993 + * The Regents of the University of California. All rights reserved. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include +#include + +char *__findenv(const char *name, int len, int *offset); + +/* + * __findenv -- + * Returns pointer to value associated with name, if any, else NULL. + * Starts searching within the environmental array at offset. + * Sets offset to be the offset of the name/value combination in the + * environmental array, for use by putenv(3), setenv(3) and unsetenv(3). + * Explicitly removes '=' in argument name. + * + * This routine *should* be a static; don't use it. + */ +char * +__findenv(const char *name, int len, int *offset) +{ + extern char **environ; + int i; + const char *np; + char **p, *cp; + + if (name == NULL || environ == NULL) + return (NULL); + for (p = environ + *offset; (cp = *p) != NULL; ++p) { + for (np = name, i = len; i && *cp; i--) + if (*cp++ != *np++) + break; + if (i == 0 && *cp++ == '=') { + *offset = p - environ; + return (cp); + } + } + return (NULL); +} + +/* + * getenv -- + * Returns ptr to value associated with name, if any, else NULL. + */ +char * +getenv(const char *name) +{ + int offset = 0; + const char *np; + + for (np = name; *np && *np != '='; ++np) + ; + return (__findenv(name, (int)(np - name), &offset)); +} diff --git a/lisp/setenv.c b/lisp/setenv.c new file mode 100644 index 0000000..089ab92 --- /dev/null +++ b/lisp/setenv.c @@ -0,0 +1,178 @@ +/* $OpenBSD: setenv.c,v 1.13 2010/08/23 22:31:50 millert Exp $ */ +/* + * Copyright (c) 1987 Regents of the University of California. + * All rights reserved. + * + * 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. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. + */ + +#include +#include +#include + +char *__findenv(const char *name, int len, int *offset); + +extern char **environ; +static char **lastenv; /* last value of environ */ + +/* + * putenv -- + * Add a name=value string directly to the environmental, replacing + * any current value. + */ +int +putenv(char *str) +{ + char **P, *cp; + size_t cnt; + int offset = 0; + + for (cp = str; *cp && *cp != '='; ++cp) + ; + if (*cp != '=') { + errno = EINVAL; + return (-1); /* missing `=' in string */ + } + + if (__findenv(str, (int)(cp - str), &offset) != NULL) { + environ[offset++] = str; + /* could be set multiple times */ + while (__findenv(str, (int)(cp - str), &offset)) { + for (P = &environ[offset];; ++P) + if (!(*P = *(P + 1))) + break; + } + return (0); + } + + /* create new slot for string */ + for (P = environ; *P != NULL; P++) + ; + cnt = P - environ; + P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); + if (!P) + return (-1); + if (lastenv != environ) + memcpy(P, environ, cnt * sizeof(char *)); + lastenv = environ = P; + environ[cnt] = str; + environ[cnt + 1] = NULL; + return (0); +} + +/* + * setenv -- + * Set the value of the environmental variable "name" to be + * "value". If rewrite is set, replace any current value. + */ +int +setenv(const char *name, const char *value, int rewrite) +{ + char *C, **P; + const char *np; + int l_value, offset = 0; + + for (np = name; *np && *np != '='; ++np) + ; +#ifdef notyet + if (*np) { + errno = EINVAL; + return (-1); /* has `=' in name */ + } +#endif + + l_value = strlen(value); + if ((C = __findenv(name, (int)(np - name), &offset)) != NULL) { + int tmpoff = offset + 1; + if (!rewrite) + return (0); +#if 0 /* XXX - existing entry may not be writable */ + if (strlen(C) >= l_value) { /* old larger; copy over */ + while ((*C++ = *value++)) + ; + return (0); + } +#endif + /* could be set multiple times */ + while (__findenv(name, (int)(np - name), &tmpoff)) { + for (P = &environ[tmpoff];; ++P) + if (!(*P = *(P + 1))) + break; + } + } else { /* create new slot */ + size_t cnt; + + for (P = environ; *P != NULL; P++) + ; + cnt = P - environ; + P = (char **)realloc(lastenv, sizeof(char *) * (cnt + 2)); + if (!P) + return (-1); + if (lastenv != environ) + memcpy(P, environ, cnt * sizeof(char *)); + lastenv = environ = P; + offset = cnt; + environ[cnt + 1] = NULL; + } + if (!(environ[offset] = /* name + `=' + value */ + malloc((size_t)((int)(np - name) + l_value + 2)))) + return (-1); + for (C = environ[offset]; (*C = *name++) && *C != '='; ++C) + ; + for (*C++ = '='; (*C++ = *value++); ) + ; + return (0); +} + +/* + * unsetenv(name) -- + * Delete environmental variable "name". + */ +int +unsetenv(const char *name) +{ + char **P; + const char *np; + int offset = 0; + + if (!name || !*name) { + errno = EINVAL; + return (-1); + } + for (np = name; *np && *np != '='; ++np) + ; + if (*np) { + errno = EINVAL; + return (-1); /* has `=' in name */ + } + + /* could be set multiple times */ + while (__findenv(name, (int)(np - name), &offset)) { + for (P = &environ[offset];; ++P) + if (!(*P = *(P + 1))) + break; + } + return (0); +} diff --git a/realpath.c b/realpath.c index 4d58b75..21af4cf 100644 --- a/realpath.c +++ b/realpath.c @@ -1,9 +1,6 @@ +/* $OpenBSD: realpath.c,v 1.14 2011/07/24 21:03:00 miod Exp $ */ /* - * Copyright (c) 1994 - * The Regents of the University of California. All rights reserved. - * - * This code is derived from software contributed to Berkeley by - * Jan-Simon Pendry. + * Copyright (c) 2003 Constantin S. Svintsoff * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,18 +10,14 @@ * 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. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by the University of - * California, Berkeley and its contributors. - * 4. Neither the name of the University nor the names of its contributors - * may be used to endorse or promote products derived from this software - * without specific prior written permission. + * 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 REGENTS AND CONTRIBUTORS ``AS IS'' AND + * 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 REGENTS OR CONTRIBUTORS BE LIABLE + * 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) @@ -33,176 +26,187 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -/* $XFree86: xc/programs/xedit/realpath.c,v 1.4 2000/02/12 20:45:45 dawes Exp $ */ - -#if defined(LIBC_SCCS) && !defined(lint) -static char sccsid[] = "@(#)realpath.c 8.1 (Berkeley) 2/16/94"; -#endif /* LIBC_SCCS and not lint */ #include -#include #include #include -#include #include #include #include -#ifndef LISP -#include "xedit.h" -#endif - -#if defined(__Lynx__) -#define NO_FCHDIR -#endif - -#if defined(ISC) -#ifndef MAXPATHLEN -#define MAXPATHLEN 1024 -#endif -#endif -#ifndef MAXSYMLINKS -#define MAXSYMLINKS 256 -#endif - /* - * char *realpath(const char *path, char resolved_path[MAXPATHLEN]); + * char *realpath(const char *path, char resolved[PATH_MAX]); * * 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(path, resolved) - const char *path; - char *resolved; +realpath(const char *path, char *resolved) { struct stat sb; -#ifdef NO_FCHDIR - char start[MAXPATHLEN]; -#else - int fd; -#endif - int n, rootd, serrno; - char *p, *q, wbuf[MAXPATHLEN]; - int symlinks = 0; - - /* Save the starting point. */ -#ifdef NO_FCHDIR - if (getcwd(start, MAXPATHLEN) == NULL) { - (void)strcpy(resolved, "."); - return (NULL); - } -#else - if ((fd = open(".", O_RDONLY)) < 0) { - (void)strcpy(resolved, "."); + char *p, *q, *s; + size_t left_len, resolved_len; + unsigned symlinks; + int serrno, slen, mem_allocated; + char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; + + if (path[0] == '\0') { + errno = ENOENT; return (NULL); } -#endif - /* - * Find the dirname and basename from the path to be resolved. - * Change directory to the dirname component. - * lstat the basename part. - * if it is a symlink, read in the value and loop. - * if it is a directory, then change to that directory. - * get the current directory name and append the basename. - */ - (void)strncpy(resolved, path, MAXPATHLEN - 1); - resolved[MAXPATHLEN - 1] = '\0'; -loop: - q = strrchr(resolved, '/'); - if (q != NULL) { - p = q + 1; - if (q == resolved) - q = "/"; - else { - do { - --q; - } while (q > resolved && *q == '/'); - q[1] = '\0'; - q = resolved; - } - if (chdir(q) < 0) - goto err1; - } else - p = resolved; + serrno = errno; - /* Deal with the last component. */ - if (*p != '\0' && lstat(p, &sb) == 0) { - if (S_ISLNK(sb.st_mode)) { - if (++symlinks > MAXSYMLINKS) { - errno = ELOOP; - goto err1; - } - n = readlink(p, resolved, MAXPATHLEN); - if (n < 0) - goto err1; - resolved[n] = '\0'; - goto loop; - } - if (S_ISDIR(sb.st_mode)) { - if (chdir(p) < 0) - goto err1; - p = ""; + if (resolved == NULL) { + resolved = malloc(PATH_MAX); + if (resolved == NULL) + return (NULL); + mem_allocated = 1; + } else + mem_allocated = 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 (mem_allocated) + free(resolved); + else + strlcpy(resolved, ".", PATH_MAX); + return (NULL); } + resolved_len = strlen(resolved); + left_len = strlcpy(left, path, sizeof(left)); + } + if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; } /* - * Save the last component name and get the full pathname of - * the current directory. - */ - (void)strcpy(wbuf, p); - if (getcwd(resolved, MAXPATHLEN) == 0) - goto err1; - - /* - * Join the two strings together, ensuring that the right thing - * happens if the last component is empty, or the dirname is root. + * Iterate over path components in `left'. */ - if (resolved[0] == '/' && resolved[1] == '\0') - rootd = 1; - else - rootd = 0; - - if (*wbuf) { - if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { + 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)) { errno = ENAMETOOLONG; - goto err1; + goto err; + } + 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) { + errno = ENAMETOOLONG; + goto err; + } + resolved[resolved_len++] = '/'; + resolved[resolved_len] = '\0'; + } + if (next_token[0] == '\0') + 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; } - if (rootd == 0) - (void)strcat(resolved, "/"); - (void)strcat(resolved, wbuf); - } - /* Go back to where we came from. */ -#ifdef NO_FCHDIR - if (chdir(start) < 0) -#else - if (fchdir(fd) < 0) -#endif - { - serrno = errno; - goto err2; + /* + * Append the next path component and lstat() it. If + * lstat() fails we still can return successfully if + * there are no more path components left. + */ + resolved_len = strlcat(resolved, next_token, PATH_MAX); + if (resolved_len >= PATH_MAX) { + errno = ENAMETOOLONG; + goto err; + } + if (lstat(resolved, &sb) != 0) { + if (errno == ENOENT && p == NULL) { + errno = serrno; + return (resolved); + } + goto err; + } + if (S_ISLNK(sb.st_mode)) { + if (symlinks++ > MAXSYMLINKS) { + errno = ELOOP; + goto err; + } + slen = readlink(resolved, symlink, sizeof(symlink) - 1); + if (slen < 0) + goto err; + 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)) { + errno = ENAMETOOLONG; + goto err; + } + symlink[slen] = '/'; + symlink[slen + 1] = 0; + } + left_len = strlcat(symlink, left, sizeof(left)); + if (left_len >= sizeof(left)) { + errno = ENAMETOOLONG; + goto err; + } + } + left_len = strlcpy(left, symlink, sizeof(left)); + } } - /* It's okay if the close fails, what's an fd more or less? */ -#ifndef NO_FCHDIR - (void)close(fd); -#endif + /* + * 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); -err1: serrno = errno; -#ifdef NO_FCHDIR - (void)chdir(start); -#else - (void)fchdir(fd); -#endif -err2: -#ifndef NO_FCHDIR - (void)close(fd); -#endif - errno = serrno; +err: + if (mem_allocated) + free(resolved); return (NULL); } -- 1.7.9.2