Author: kib
Date: Tue Apr 20 10:16:44 2010
New Revision: 206893
URL: http://svn.freebsd.org/changeset/base/206893

Log:
  Slightly modernize realpath(3).
  
  SUSv4 requires that implementation returns EINVAL if supplied path is NULL,
  and ENOENT if path is empty string [1].
  Bring prototype in conformance with SUSv4, adding restrict keywords.
  Allow the resolved path buffer pointer be NULL, in which case realpath(3)
  allocates storage with malloc().
  
  PR:   kern/121897 [1]
  MFC after:    2 weeks

Modified:
  head/include/stdlib.h
  head/lib/libc/stdlib/realpath.3
  head/lib/libc/stdlib/realpath.c

Modified: head/include/stdlib.h
==============================================================================
--- head/include/stdlib.h       Tue Apr 20 08:51:21 2010        (r206892)
+++ head/include/stdlib.h       Tue Apr 20 10:16:44 2010        (r206893)
@@ -201,7 +201,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]);
 #ifndef _SETKEY_DECLARED

Modified: head/lib/libc/stdlib/realpath.3
==============================================================================
--- head/lib/libc/stdlib/realpath.3     Tue Apr 20 08:51:21 2010        
(r206892)
+++ head/lib/libc/stdlib/realpath.3     Tue Apr 20 10:16:44 2010        
(r206893)
@@ -31,7 +31,7 @@
 .\"     @(#)realpath.3 8.2 (Berkeley) 2/16/94
 .\" $FreeBSD$
 .\"
-.Dd February 16, 1994
+.Dd April 19, 2010
 .Dt REALPATH 3
 .Os
 .Sh NAME
@@ -43,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
@@ -64,7 +64,8 @@ argument
 .Em must
 refer to a buffer capable of storing at least
 .Dv PATH_MAX
-characters.
+characters, or be
+.Dv NULL .
 .Pp
 The
 .Fn realpath
@@ -82,6 +83,13 @@ 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
@@ -89,6 +97,11 @@ returns
 and
 .Fa resolved_path
 contains the pathname which caused the problem.
+If
+.Fa resolved_path
+was
+.Dv NULL ,
+then information of the failed pathname component is lost.
 .Sh ERRORS
 The function
 .Fn realpath

Modified: head/lib/libc/stdlib/realpath.c
==============================================================================
--- head/lib/libc/stdlib/realpath.c     Tue Apr 20 08:51:21 2010        
(r206892)
+++ head/lib/libc/stdlib/realpath.c     Tue Apr 20 10:16:44 2010        
(r206893)
@@ -43,23 +43,37 @@ __FBSDID("$FreeBSD$");
 #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 serrno, slen, m;
        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);
+       }
        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] = '/';
@@ -71,12 +85,19 @@ realpath(const char *path, char resolved
        } else {
                if (getcwd(resolved, PATH_MAX) == NULL) {
                        strlcpy(resolved, ".", PATH_MAX);
+                       if (m) {
+                               serrno = errno;
+                               free(resolved);
+                               errno = serrno;
+                       }
                        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);
        }
@@ -92,6 +113,8 @@ realpath(const char *path, char resolved
                p = strchr(left, '/');
                s = p ? p : left + left_len;
                if (s - left >= sizeof(next_token)) {
+                       if (m)
+                               free(resolved);
                        errno = ENAMETOOLONG;
                        return (NULL);
                }
@@ -102,6 +125,8 @@ realpath(const char *path, char resolved
                        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);
                        }
@@ -133,6 +158,8 @@ realpath(const char *path, char resolved
                 */
                resolved_len = strlcat(resolved, next_token, PATH_MAX);
                if (resolved_len >= PATH_MAX) {
+                       if (m)
+                               free(resolved);
                        errno = ENAMETOOLONG;
                        return (NULL);
                }
@@ -141,16 +168,29 @@ realpath(const char *path, char resolved
                                errno = serrno;
                                return (resolved);
                        }
+                       if (m) {
+                               serrno = errno;
+                               free(resolved);
+                               errno = serrno;
+                       }
                        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 (slen < 0) {
+                               if (m) {
+                                       serrno = errno;
+                                       free(resolved);
+                                       errno = serrno;
+                               }
                                return (NULL);
+                       }
                        symlink[slen] = '\0';
                        if (symlink[0] == '/') {
                                resolved[1] = 0;
@@ -171,6 +211,8 @@ realpath(const char *path, char resolved
                        if (p != NULL) {
                                if (symlink[slen - 1] != '/') {
                                        if (slen + 1 >= sizeof(symlink)) {
+                                               if (m)
+                                                       free(resolved);
                                                errno = ENAMETOOLONG;
                                                return (NULL);
                                        }
@@ -179,6 +221,8 @@ realpath(const char *path, char resolved
                                }
                                left_len = strlcat(symlink, left, sizeof(left));
                                if (left_len >= sizeof(left)) {
+                                       if (m)
+                                               free(resolved);
                                        errno = ENAMETOOLONG;
                                        return (NULL);
                                }
_______________________________________________
svn-src-head@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to