Module Name: src Committed By: christos Date: Thu Jun 21 21:13:07 UTC 2012
Modified Files: src/lib/libc/gen: getcwd.c realpath.3 Log Message: PR/46618: Onno van der Linden: realpath(3) isn't SUSv4 compliant (and causes flactag 2.0.4 to dump core). Fix to accept a NULL argument for resolvedpath. To generate a diff of this commit: cvs rdiff -u -r1.51 -r1.52 src/lib/libc/gen/getcwd.c cvs rdiff -u -r1.12 -r1.13 src/lib/libc/gen/realpath.3 Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/lib/libc/gen/getcwd.c diff -u src/lib/libc/gen/getcwd.c:1.51 src/lib/libc/gen/getcwd.c:1.52 --- src/lib/libc/gen/getcwd.c:1.51 Tue Mar 13 17:13:35 2012 +++ src/lib/libc/gen/getcwd.c Thu Jun 21 17:13:07 2012 @@ -1,4 +1,4 @@ -/* $NetBSD: getcwd.c,v 1.51 2012/03/13 21:13:35 christos Exp $ */ +/* $NetBSD: getcwd.c,v 1.52 2012/06/21 21:13:07 christos Exp $ */ /* * Copyright (c) 1989, 1991, 1993, 1995 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95"; #else -__RCSID("$NetBSD: getcwd.c,v 1.51 2012/03/13 21:13:35 christos Exp $"); +__RCSID("$NetBSD: getcwd.c,v 1.52 2012/06/21 21:13:07 christos Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -61,30 +61,36 @@ __weak_alias(realpath,_realpath) #endif /* - * char *realpath(const char *path, char resolved[MAXPATHLEN]); + * char *realpath(const char *path, char *resolved); * * 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) +realpath(const char * __restrict path, char * __restrict resolved) { struct stat sb; int idx = 0, nlnk = 0; const char *q; - char *p, wbuf[2][MAXPATHLEN]; + char *p, wbuf[2][MAXPATHLEN], *fres; size_t len; ssize_t n; - _DIAGASSERT(resolved != NULL); - /* POSIX sez we must test for this */ if (path == NULL) { errno = EINVAL; return NULL; } + if (resolved == NULL) { + fres = resolved = malloc(MAXPATHLEN); + if (resolved == NULL) + return NULL; + } else + fres = NULL; + + /* * Build real path one by one with paying an attention to ., * .. and symbolic link. @@ -96,10 +102,10 @@ realpath(const char *path, char *resolve */ p = resolved; - if (*path == 0) { - *p = 0; + if (*path == '\0') { + *p = '\0'; errno = ENOENT; - return (NULL); + goto out; } /* If relative path, start from current working directory. */ @@ -107,8 +113,8 @@ realpath(const char *path, char *resolve /* check for resolved pointer to appease coverity */ if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { p[0] = '.'; - p[1] = 0; - return (NULL); + p[1] = '\0'; + goto out; } len = strlen(resolved); if (len > 1) @@ -120,18 +126,18 @@ loop: while (*path == '/') path++; - if (*path == 0) { + if (*path == '\0') { if (p == resolved) *p++ = '/'; - *p = 0; - return (resolved); + *p = '\0'; + return resolved; } /* Find the end of this component. */ q = path; do q++; - while (*q != '/' && *q != 0); + while (*q != '/' && *q != '\0'); /* Test . or .. */ if (path[0] == '.') { @@ -143,7 +149,7 @@ loop: /* Trim the last component. */ if (p != resolved) while (*--p != '/') - ; + continue; path = q; goto loop; } @@ -154,39 +160,39 @@ loop: errno = ENAMETOOLONG; if (p == resolved) *p++ = '/'; - *p = 0; - return (NULL); + *p = '\0'; + goto out; } p[0] = '/'; memcpy(&p[1], path, /* LINTED We know q > path. */ q - path); - p[1 + q - path] = 0; + p[1 + q - path] = '\0'; /* * If this component is a symlink, toss it and prepend link * target to unresolved path. */ - if (lstat(resolved, &sb) == -1) { - return (NULL); - } + if (lstat(resolved, &sb) == -1) + goto out; + if (S_ISLNK(sb.st_mode)) { if (nlnk++ >= MAXSYMLINKS) { errno = ELOOP; - return (NULL); + goto out; } n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); if (n < 0) return (NULL); if (n == 0) { errno = ENOENT; - return (NULL); + goto out; } /* Append unresolved path to link target and switch to it. */ if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { errno = ENAMETOOLONG; - return (NULL); + goto out; } memcpy(&wbuf[idx][n], q, len + 1); path = wbuf[idx]; @@ -199,13 +205,16 @@ loop: } if (*q == '/' && !S_ISDIR(sb.st_mode)) { errno = ENOTDIR; - return (NULL); + goto out; } /* Advance both resolved and unresolved path. */ p += 1 + q - path; path = q; goto loop; +out: + free(fres); + return NULL; } char * Index: src/lib/libc/gen/realpath.3 diff -u src/lib/libc/gen/realpath.3:1.12 src/lib/libc/gen/realpath.3:1.13 --- src/lib/libc/gen/realpath.3:1.12 Sat Aug 13 15:53:53 2005 +++ src/lib/libc/gen/realpath.3 Thu Jun 21 17:13:07 2012 @@ -1,4 +1,4 @@ -.\" $NetBSD: realpath.3,v 1.12 2005/08/13 19:53:53 elad Exp $ +.\" $NetBSD: realpath.3,v 1.13 2012/06/21 21:13:07 christos Exp $ .\" .\" Copyright (c) 1994 .\" The Regents of the University of California. All rights reserved. @@ -32,7 +32,7 @@ .\" .\" from: @(#)realpath.3 8.2 (Berkeley) 2/16/94 .\" -.Dd August 13, 2005 +.Dd June 21, 2012 .Dt REALPATH 3 .Os .Sh NAME @@ -44,7 +44,7 @@ .In sys/param.h .In stdlib.h .Ft "char *" -.Fn realpath "const char *pathname" "char resolvedname[MAXPATHLEN]" +.Fn realpath "const char * restrict pathname" "char * restrict resolvedname" .Sh DESCRIPTION The .Fn realpath @@ -73,6 +73,12 @@ function will resolve both absolute and and return the absolute pathname corresponding to .Fa pathname . .Sh RETURN VALUES +If +.Fa resolvednamed +is +.Dv NULL , +it will be allocated and the returned pointer can be deallocated using +.Xr free 3 . The .Fn realpath function returns @@ -84,7 +90,9 @@ returns .Dv NULL , and .Fa resolvedname -contains the pathname which caused the problem. +was not allocated by +.Xr realpath , +it will contain the pathname which caused the problem. .Sh ERRORS The function .Fn realpath @@ -95,17 +103,31 @@ for any of the errors specified for the .Xr close 2 , .Xr fchdir 2 , .Xr lstat 2 , +.Xr malloc 3 , .Xr open 2 , .Xr readlink 2 and .Xr getcwd 3 . .Sh SEE ALSO .Xr getcwd 3 +.Sh STANDARDS +.Fn realpath +first appeared in +.St -xpg4.2 +and is part of +.St -p1003.1-2001 . .Sh HISTORY The .Fn realpath function call first appeared in .Bx 4.4 . +In +.Nx 7.0 +the function was updated to accept a +.Dv NULL +pointer for the +.Fa resolvedname +argument. .Sh BUGS This implementation of .Fn realpath