realpath(3): Upgrade to POSIX IEEE Std 1003.1-2008
authorJohn Marino <draco@marino.st>
Sat, 5 May 2012 16:07:58 +0000 (18:07 +0200)
committerJohn Marino <draco@marino.st>
Sat, 5 May 2012 16:43:31 +0000 (18:43 +0200)
Recent updates to realpath implements some of the missing POSIX
functionality, but the requirement to allocate memory for the pointer
returned by the function when a null pointer is passed to the
resolved_path argument was missing.

The prototype changes in the following ways:
1.  The restrict type qualifier is added to both arguments
2.  The second argument changes from "char resolved[PATH_MAX]" to
    "char * resolved"

The new prototype is backwards-compatible with the old one.

This should bring realpath up to Open Group Specifications Issue 7
IEEE Std 1003.1-2008
http://pubs.opengroup.org/onlinepubs/9699919799/functions/realpath.html

Taken from:
FreeBSD SVN 206893 (20 APR 2010)
FreeBSD SVN 206898 (20 APR 2010)
FreeBSD SVN 217144 (08 JAN 2011)
FreeBSD SVN 227090 (04 NOV 2011)

include/stdlib.h
lib/libc/stdlib/realpath.3
lib/libc/stdlib/realpath.c

index be88f6d..cdf086d 100644 (file)
@@ -32,7 +32,6 @@
  *
  *     @(#)stdlib.h    8.5 (Berkeley) 5/19/95
  * $FreeBSD: src/include/stdlib.h,v 1.67 2008/07/22 11:40:42 ache Exp $
- * $DragonFly: src/include/stdlib.h,v 1.22 2008/06/05 17:53:10 swildner Exp $
  */
 
 #ifndef _STDLIB_H_
@@ -208,7 +207,7 @@ int  posix_openpt(int);
 char   *ptsname(int);
 int     putenv(char *);
 long    random(void);
-char   *realpath(const char *, char resolved_path[]);
+char   *realpath(const char * __restrict, char * __restrict);
 unsigned short
        *seed48(unsigned short[3]);
 int     setkey(const char *);
index e61b814..101e108 100644 (file)
 .\" SUCH DAMAGE.
 .\"
 .\"     @(#)realpath.3 8.2 (Berkeley) 2/16/94
-.\" $FreeBSD: src/lib/libc/stdlib/realpath.3,v 1.14 2007/01/09 00:28:10 imp Exp $
-.\" $DragonFly: src/lib/libc/stdlib/realpath.3,v 1.2 2003/06/17 04:26:46 dillon Exp $
+.\" $FreeBSD: src/lib/libc/stdlib/realpath.3 SVN 227090 2011/11/04 ed $
 .\"
-.Dd February 16, 1994
+.Dd May 5, 2012
 .Dt REALPATH 3
 .Os
 .Sh NAME
@@ -44,7 +43,7 @@
 .In sys/param.h
 .In stdlib.h
 .Ft "char *"
-.Fn realpath "const char *pathname" "char resolved_path[PATH_MAX]"
+.Fn realpath "const char *pathname" "char *resolved_path"
 .Sh DESCRIPTION
 The
 .Fn realpath
@@ -57,15 +56,16 @@ and
 in
 .Fa pathname ,
 and copies the resulting absolute pathname into
-the memory referenced by
+the memory pointed to by
 .Fa resolved_path .
 The
 .Fa resolved_path
 argument
 .Em must
-refer to a buffer capable of storing at least
+point to a buffer capable of storing at least
 .Dv PATH_MAX
-characters.
+characters, or be
+.Dv NULL .
 .Pp
 The
 .Fn realpath
@@ -83,13 +83,22 @@ The
 function returns
 .Fa resolved_path
 on success.
+If the function was supplied
+.Dv NULL
+as
+.Fa resolved_path ,
+and operation did not cause errors, the returned value is
+a null-terminated string in a buffer allocated by a call to
+.Fn malloc 3 .
 If an error occurs,
 .Fn realpath
 returns
 .Dv NULL ,
-and
+and if
 .Fa resolved_path
-contains the pathname which caused the problem.
+is not
+.Dv NULL ,
+the array that it points to contains the pathname which caused the problem.
 .Sh ERRORS
 The function
 .Fn realpath
@@ -100,6 +109,18 @@ for any of the errors specified for the library functions
 .Xr readlink 2
 and
 .Xr getcwd 3 .
+.Sh SEE ALSO
+.Xr getcwd 3
+.\" .Sh STANDARDS
+.\" The
+.\" .Fn realpath
+.\" function conforms to
+.\" .St -p1003.1-2008 .
+.Sh HISTORY
+The
+.Fn realpath
+function first appeared in
+.Bx 4.4 .
 .Sh CAVEATS
 This implementation of
 .Fn realpath
@@ -112,10 +133,3 @@ under certain circumstances, return a relative
 .Fa resolved_path
 when given a relative
 .Fa pathname .
-.Sh "SEE ALSO"
-.Xr getcwd 3
-.Sh HISTORY
-The
-.Fn realpath
-function first appeared in
-.Bx 4.4 .
index d2ab03e..ccffda6 100644 (file)
@@ -25,9 +25,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- * @(#)realpath.c      8.1 (Berkeley) 2/16/94
- * $FreeBSD: src/lib/libc/stdlib/realpath.c,v 1.20 2003/05/28 08:23:01 fjoe Exp $
- * $DragonFly: src/lib/libc/stdlib/realpath.c,v 1.4 2005/04/28 13:47:15 joerg Exp $
+ * $FreeBSD: src/lib/libc/stdlib/realpath.c SVN 227090 2011/11/04 ed $
  */
 
 #include "namespace.h"
 #include "un-namespace.h"
 
 /*
- * 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(const char *path, char resolved[PATH_MAX])
+realpath(const char * __restrict path, char * __restrict resolved)
 {
        struct stat sb;
        char *p, *q, *s;
        size_t left_len, resolved_len;
        unsigned symlinks;
-       int serrno, slen;
+       int m, serrno, slen;
        char left[PATH_MAX], next_token[PATH_MAX], my_symlink[PATH_MAX];
 
-       serrno = errno;
-       symlinks = 0;
        if (path == NULL) {
                errno = EINVAL;
                return (NULL);
@@ -66,7 +60,17 @@ realpath(const char *path, char resolved[PATH_MAX])
        if (path[0] == '\0') {
                errno = ENOENT;
                return (NULL);
-       } else if (path[0] == '/') {
+       }
+       serrno = errno;
+       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')
@@ -75,13 +79,20 @@ realpath(const char *path, char resolved[PATH_MAX])
                left_len = strlcpy(left, path + 1, sizeof(left));
        } else {
                if (getcwd(resolved, PATH_MAX) == NULL) {
-                       strlcpy(resolved, ".", PATH_MAX);
+                       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);
        }
@@ -96,7 +107,9 @@ realpath(const char *path, char resolved[PATH_MAX])
                 */
                p = strchr(left, '/');
                s = p ? p : left + left_len;
-               if (s >= left + sizeof(next_token)) {
+               if (s - left >= sizeof(next_token)) {
+                       if (m)
+                               free(resolved);
                        errno = ENAMETOOLONG;
                        return (NULL);
                }
@@ -107,6 +120,8 @@ realpath(const char *path, char resolved[PATH_MAX])
                        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);
                        }
@@ -138,6 +153,8 @@ realpath(const char *path, char resolved[PATH_MAX])
                 */
                resolved_len = strlcat(resolved, next_token, PATH_MAX);
                if (resolved_len >= PATH_MAX) {
+                       if (m)
+                               free(resolved);
                        errno = ENAMETOOLONG;
                        return (NULL);
                }
@@ -146,16 +163,23 @@ realpath(const char *path, char resolved[PATH_MAX])
                                errno = serrno;
                                return (resolved);
                        }
+                       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, my_symlink, sizeof(my_symlink) - 1);
-                       if (slen < 0)
+                       if (slen < 0) {
+                               if (m)
+                                       free(resolved);
                                return (NULL);
+                       }
                        my_symlink[slen] = '\0';
                        if (my_symlink[0] == '/') {
                                resolved[1] = 0;
@@ -176,14 +200,19 @@ realpath(const char *path, char resolved[PATH_MAX])
                        if (p != NULL) {
                                if (my_symlink[slen - 1] != '/') {
                                        if (slen + 1 >= (int)sizeof(my_symlink)) {
+                                               if (m)
+                                                       free(resolved);
                                                errno = ENAMETOOLONG;
                                                return (NULL);
                                        }
                                        my_symlink[slen] = '/';
                                        my_symlink[slen + 1] = 0;
                                }
-                               left_len = strlcat(my_symlink, left, sizeof(left));
+                               left_len = strlcat(my_symlink, left,
+                                   sizeof(my_symlink));
                                if (left_len >= sizeof(left)) {
+                                       if (m)
+                                               free(resolved);
                                        errno = ENAMETOOLONG;
                                        return (NULL);
                                }