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 MFC after: 3 weeks
This commit is contained in:
parent
71b310be7b
commit
fdbe55fccb
@ -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
|
||||
|
@ -132,8 +132,29 @@ realpath(const char * __restrict path, char * __restrict resolved)
|
||||
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, char * __restrict resolved)
|
||||
}
|
||||
|
||||
/*
|
||||
* 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, char * __restrict resolved)
|
||||
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);
|
||||
|
Loading…
Reference in New Issue
Block a user