Skip site navigation (1)Skip section navigation (2)
Date:      Fri, 1 Jun 2012 14:40:16 +0000 (UTC)
From:      Konstantin Belousov <kib@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-9@freebsd.org
Subject:   svn commit: r236400 - stable/9/lib/libc/stdlib
Message-ID:  <201206011440.q51EeGII024908@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: kib
Date: Fri Jun  1 14:40:16 2012
New Revision: 236400
URL: http://svn.freebsd.org/changeset/base/236400

Log:
  MFC r235266:
  According to SUSv4, realpath(3) must fail if
    [ENOENT]  A component of file_name does not name an existing file or
        file_name points to an empty string.
    [ENOTDIR] A component of the path prefix is not a directory, or the
        file_name argument contains at least one non- <slash> character
        and ends with one or more trailing <slash> characters and the last
        pathname component names an existing file that is neither a
        directory nor a symbolic link to a directory.
  Add checks for the listed conditions, and set errno accordingly.
  
  Update the realpath(3) manpage to mention SUS behaviour. Remove the
  requirement to include sys/param.h before stdlib.h.
  
  PR:	128933

Modified:
  stable/9/lib/libc/stdlib/realpath.3
  stable/9/lib/libc/stdlib/realpath.c
Directory Properties:
  stable/9/lib/libc/   (props changed)

Modified: stable/9/lib/libc/stdlib/realpath.3
==============================================================================
--- stable/9/lib/libc/stdlib/realpath.3	Fri Jun  1 14:29:59 2012	(r236399)
+++ stable/9/lib/libc/stdlib/realpath.3	Fri Jun  1 14:40:16 2012	(r236400)
@@ -31,7 +31,7 @@
 .\"     @(#)realpath.3	8.2 (Berkeley) 2/16/94
 .\" $FreeBSD$
 .\"
-.Dd April 19, 2010
+.Dd May 11, 2012
 .Dt REALPATH 3
 .Os
 .Sh NAME
@@ -40,7 +40,6 @@
 .Sh LIBRARY
 .Lb libc
 .Sh SYNOPSIS
-.In sys/param.h
 .In stdlib.h
 .Ft "char *"
 .Fn realpath "const char *pathname" "char *resolved_path"
@@ -72,11 +71,12 @@ The
 function will resolve both absolute and relative paths
 and return the absolute pathname corresponding to
 .Fa pathname .
-All but the last component of
+All components of
 .Fa pathname
 must exist when
 .Fn realpath
-is called.
+is called, and all but the last component must name either directories or
+symlinks pointing to the directories.
 .Sh "RETURN VALUES"
 The
 .Fn realpath

Modified: stable/9/lib/libc/stdlib/realpath.c
==============================================================================
--- stable/9/lib/libc/stdlib/realpath.c	Fri Jun  1 14:29:59 2012	(r236399)
+++ stable/9/lib/libc/stdlib/realpath.c	Fri Jun  1 14:40:16 2012	(r236400)
@@ -132,8 +132,29 @@ realpath(const char * __restrict path, c
 			resolved[resolved_len++] = '/';
 			resolved[resolved_len] = '\0';
 		}
-		if (next_token[0] == '\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) {
@@ -151,9 +172,7 @@ realpath(const char * __restrict path, c
 		}
 
 		/*
-		 * Append the next path component and lstat() it. If
-		 * lstat() fails we still can return successfully if
-		 * there are no more path components left.
+		 * Append the next path component and lstat() it.
 		 */
 		resolved_len = strlcat(resolved, next_token, PATH_MAX);
 		if (resolved_len >= PATH_MAX) {
@@ -163,10 +182,8 @@ realpath(const char * __restrict path, c
 			return (NULL);
 		}
 		if (lstat(resolved, &sb) != 0) {
-			if (errno == ENOENT && p == NULL) {
-				errno = serrno;
-				return (resolved);
-			}
+			if (errno != ENOENT || p != NULL)
+				errno = ENOTDIR;
 			if (m)
 				free(resolved);
 			return (NULL);



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201206011440.q51EeGII024908>