version 1.36.2.1, 2005/08/14 22:08:44 |
version 1.50.4.2, 2012/10/30 18:58:46 |
Line 50 __RCSID("$NetBSD$"); |
|
Line 50 __RCSID("$NetBSD$"); |
|
#include <stdlib.h> |
#include <stdlib.h> |
#include <string.h> |
#include <string.h> |
#include <unistd.h> |
#include <unistd.h> |
|
#include <ssp/ssp.h> |
|
|
#include "extern.h" |
#include "extern.h" |
|
|
#ifdef __weak_alias |
#ifdef __weak_alias |
__weak_alias(getcwd,_getcwd) |
__weak_alias(getcwd,_getcwd) |
|
__weak_alias(_sys_getcwd,_getcwd) |
__weak_alias(realpath,_realpath) |
__weak_alias(realpath,_realpath) |
#endif |
#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 |
* Find the real name of path, by removing all ".", ".." and symlink |
* components. Returns (resolved) on success, or (NULL) on failure, |
* components. Returns (resolved) on success, or (NULL) on failure, |
* in which case the path which caused trouble is left in (resolved). |
* in which case the path which caused trouble is left in (resolved). |
*/ |
*/ |
char * |
char * |
realpath(const char *path, char *resolved) |
realpath(const char * __restrict path, char * __restrict resolved) |
{ |
{ |
struct stat sb; |
struct stat sb; |
int idx = 0, n, nlnk = 0; |
int idx = 0, nlnk = 0; |
const char *q; |
const char *q; |
char *p, wbuf[2][MAXPATHLEN]; |
char *p, wbuf[2][MAXPATHLEN], *fres; |
size_t len; |
size_t len; |
|
ssize_t n; |
|
|
|
/* 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; |
|
|
_DIAGASSERT(path != NULL); |
|
_DIAGASSERT(resolved != NULL); |
|
|
|
/* |
/* |
* Build real path one by one with paying an attention to ., |
* Build real path one by one with paying an attention to ., |
Line 88 realpath(const char *path, char *resolve |
|
Line 102 realpath(const char *path, char *resolve |
|
*/ |
*/ |
p = resolved; |
p = resolved; |
|
|
if (*path == 0) { |
if (*path == '\0') { |
*p = 0; |
*p = '\0'; |
errno = ENOENT; |
errno = ENOENT; |
return (NULL); |
goto out; |
} |
} |
|
|
/* If relative path, start from current working directory. */ |
/* If relative path, start from current working directory. */ |
if (*path != '/') { |
if (*path != '/') { |
if (getcwd(resolved, MAXPATHLEN) == NULL) { |
/* check for resolved pointer to appease coverity */ |
|
if (resolved && getcwd(resolved, MAXPATHLEN) == NULL) { |
p[0] = '.'; |
p[0] = '.'; |
p[1] = 0; |
p[1] = '\0'; |
return (NULL); |
goto out; |
} |
} |
len = strlen(resolved); |
len = strlen(resolved); |
if (len > 1) |
if (len > 1) |
|
|
while (*path == '/') |
while (*path == '/') |
path++; |
path++; |
|
|
if (*path == 0) { |
if (*path == '\0') { |
if (p == resolved) |
if (p == resolved) |
*p++ = '/'; |
*p++ = '/'; |
*p = 0; |
*p = '\0'; |
return (resolved); |
return resolved; |
} |
} |
|
|
/* Find the end of this component. */ |
/* Find the end of this component. */ |
q = path; |
q = path; |
do |
do |
q++; |
q++; |
while (*q != '/' && *q != 0); |
while (*q != '/' && *q != '\0'); |
|
|
/* Test . or .. */ |
/* Test . or .. */ |
if (path[0] == '.') { |
if (path[0] == '.') { |
|
|
/* Trim the last component. */ |
/* Trim the last component. */ |
if (p != resolved) |
if (p != resolved) |
while (*--p != '/') |
while (*--p != '/') |
; |
continue; |
path = q; |
path = q; |
goto loop; |
goto loop; |
} |
} |
|
|
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
if (p == resolved) |
if (p == resolved) |
*p++ = '/'; |
*p++ = '/'; |
*p = 0; |
*p = '\0'; |
return (NULL); |
goto out; |
} |
} |
p[0] = '/'; |
p[0] = '/'; |
memcpy(&p[1], path, |
memcpy(&p[1], path, |
/* LINTED We know q > path. */ |
/* LINTED We know q > path. */ |
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 |
* If this component is a symlink, toss it and prepend link |
* target to unresolved path. |
* target to unresolved path. |
*/ |
*/ |
if (lstat(resolved, &sb) == -1) { |
if (lstat(resolved, &sb) == -1) |
return (NULL); |
goto out; |
} |
|
if (S_ISLNK(sb.st_mode)) { |
if (S_ISLNK(sb.st_mode)) { |
if (nlnk++ >= MAXSYMLINKS) { |
if (nlnk++ >= MAXSYMLINKS) { |
errno = ELOOP; |
errno = ELOOP; |
return (NULL); |
goto out; |
} |
} |
n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); |
n = readlink(resolved, wbuf[idx], sizeof(wbuf[0]) - 1); |
if (n < 0) |
if (n < 0) |
return (NULL); |
goto out; |
if (n == 0) { |
if (n == 0) { |
errno = ENOENT; |
errno = ENOENT; |
return (NULL); |
goto out; |
} |
} |
|
|
/* Append unresolved path to link target and switch to it. */ |
/* Append unresolved path to link target and switch to it. */ |
if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { |
if (n + (len = strlen(q)) + 1 > sizeof(wbuf[0])) { |
errno = ENAMETOOLONG; |
errno = ENAMETOOLONG; |
return (NULL); |
goto out; |
} |
} |
memcpy(&wbuf[idx][n], q, len + 1); |
memcpy(&wbuf[idx][n], q, len + 1); |
path = wbuf[idx]; |
path = wbuf[idx]; |
|
|
} |
} |
if (*q == '/' && !S_ISDIR(sb.st_mode)) { |
if (*q == '/' && !S_ISDIR(sb.st_mode)) { |
errno = ENOTDIR; |
errno = ENOTDIR; |
return (NULL); |
goto out; |
} |
} |
|
|
/* Advance both resolved and unresolved path. */ |
/* Advance both resolved and unresolved path. */ |
p += 1 + q - path; |
p += 1 + q - path; |
path = q; |
path = q; |
goto loop; |
goto loop; |
|
out: |
|
free(fres); |
|
return NULL; |
} |
} |
|
|
char * |
char * |
getcwd(char *pt, size_t size) |
__ssp_real(getcwd)(char *pt, size_t size) |
{ |
{ |
char *npt; |
char *npt; |
|
|