| version 1.1.1.2, 1995/02/25 09:11:43 |
version 1.1.1.3, 1998/02/02 00:11:25 |
|
|
| /* |
/* |
| * Copyright (c) 1989, 1991, 1993 |
* Copyright (c) 1989, 1991, 1993, 1995 |
| * The Regents of the University of California. All rights reserved. |
* The Regents of the University of California. All rights reserved. |
| * |
* |
| |
* This code is derived from software contributed to Berkeley by |
| |
* Jan-Simon Pendry. |
| |
* |
| * Redistribution and use in source and binary forms, with or without |
* Redistribution and use in source and binary forms, with or without |
| * modification, are permitted provided that the following conditions |
* modification, are permitted provided that the following conditions |
| * are met: |
* are met: |
|
|
| */ |
*/ |
| |
|
| #if defined(LIBC_SCCS) && !defined(lint) |
#if defined(LIBC_SCCS) && !defined(lint) |
| static char sccsid[] = "@(#)getcwd.c 8.1 (Berkeley) 6/4/93"; |
static char sccsid[] = "@(#)getcwd.c 8.5 (Berkeley) 2/7/95"; |
| #endif /* LIBC_SCCS and not lint */ |
#endif /* LIBC_SCCS and not lint */ |
| |
|
| #include <sys/param.h> |
#include <sys/param.h> |
| #include <sys/stat.h> |
#include <sys/stat.h> |
| |
|
| #include <errno.h> |
|
| #include <dirent.h> |
#include <dirent.h> |
| |
#include <errno.h> |
| |
#include <fcntl.h> |
| #include <stdio.h> |
#include <stdio.h> |
| #include <stdlib.h> |
#include <stdlib.h> |
| #include <string.h> |
#include <string.h> |
| #include <unistd.h> |
#include <unistd.h> |
| |
|
| |
static char *getcwd_physical __P((char *, size_t)); |
| |
|
| #define ISDOT(dp) \ |
#define ISDOT(dp) \ |
| (dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ |
(dp->d_name[0] == '.' && (dp->d_name[1] == '\0' || \ |
| dp->d_name[1] == '.' && dp->d_name[2] == '\0')) |
dp->d_name[1] == '.' && dp->d_name[2] == '\0')) |
|
|
| char *pt; |
char *pt; |
| size_t size; |
size_t size; |
| { |
{ |
| |
char *pwd; |
| |
size_t pwdlen; |
| |
dev_t dev; |
| |
ino_t ino; |
| |
struct stat s; |
| |
|
| |
/* Check $PWD -- if it's right, it's fast. */ |
| |
if ((pwd = getenv("PWD")) != NULL && pwd[0] == '/' && !stat(pwd, &s)) { |
| |
dev = s.st_dev; |
| |
ino = s.st_ino; |
| |
if (!stat(".", &s) && dev == s.st_dev && ino == s.st_ino) { |
| |
pwdlen = strlen(pwd); |
| |
if (size != 0) { |
| |
if (pwdlen + 1 > size) { |
| |
errno = ERANGE; |
| |
return (NULL); |
| |
} |
| |
} else if ((pt = malloc(pwdlen + 1)) == NULL) |
| |
return (NULL); |
| |
memmove(pt, pwd, pwdlen); |
| |
pt[pwdlen] = '\0'; |
| |
return (pt); |
| |
} |
| |
} |
| |
|
| |
return (getcwd_physical(pt, size)); |
| |
} |
| |
|
| |
/* |
| |
* char *realpath(const char *path, char resolved_path[MAXPATHLEN]); |
| |
* |
| |
* 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(path, resolved) |
| |
const char *path; |
| |
char *resolved; |
| |
{ |
| |
struct stat sb; |
| |
int fd, n, rootd, serrno; |
| |
char *p, *q, wbuf[MAXPATHLEN]; |
| |
|
| |
/* Save the starting point. */ |
| |
if ((fd = open(".", O_RDONLY)) < 0) { |
| |
(void)strcpy(resolved, "."); |
| |
return (NULL); |
| |
} |
| |
|
| |
/* |
| |
* Find the dirname and basename from the path to be resolved. |
| |
* Change directory to the dirname component. |
| |
* lstat the basename part. |
| |
* if it is a symlink, read in the value and loop. |
| |
* if it is a directory, then change to that directory. |
| |
* get the current directory name and append the basename. |
| |
*/ |
| |
(void)strncpy(resolved, path, MAXPATHLEN - 1); |
| |
resolved[MAXPATHLEN - 1] = '\0'; |
| |
loop: |
| |
q = strrchr(resolved, '/'); |
| |
if (q != NULL) { |
| |
p = q + 1; |
| |
if (q == resolved) |
| |
q = "/"; |
| |
else { |
| |
do { |
| |
--q; |
| |
} while (q > resolved && *q == '/'); |
| |
q[1] = '\0'; |
| |
q = resolved; |
| |
} |
| |
if (chdir(q) < 0) |
| |
goto err1; |
| |
} else |
| |
p = resolved; |
| |
|
| |
/* Deal with the last component. */ |
| |
if (lstat(p, &sb) == 0) { |
| |
if (S_ISLNK(sb.st_mode)) { |
| |
n = readlink(p, resolved, MAXPATHLEN); |
| |
if (n < 0) |
| |
goto err1; |
| |
resolved[n] = '\0'; |
| |
goto loop; |
| |
} |
| |
if (S_ISDIR(sb.st_mode)) { |
| |
if (chdir(p) < 0) |
| |
goto err1; |
| |
p = ""; |
| |
} |
| |
} |
| |
|
| |
/* |
| |
* Save the last component name and get the full pathname of |
| |
* the current directory. |
| |
*/ |
| |
(void)strcpy(wbuf, p); |
| |
|
| |
/* |
| |
* Call the inernal internal version of getcwd which |
| |
* does a physical search rather than using the $PWD short-cut |
| |
*/ |
| |
if (getcwd_physical(resolved, MAXPATHLEN) == 0) |
| |
goto err1; |
| |
|
| |
/* |
| |
* Join the two strings together, ensuring that the right thing |
| |
* happens if the last component is empty, or the dirname is root. |
| |
*/ |
| |
if (resolved[0] == '/' && resolved[1] == '\0') |
| |
rootd = 1; |
| |
else |
| |
rootd = 0; |
| |
|
| |
if (*wbuf) { |
| |
if (strlen(resolved) + strlen(wbuf) + rootd + 1 > MAXPATHLEN) { |
| |
errno = ENAMETOOLONG; |
| |
goto err1; |
| |
} |
| |
if (rootd == 0) |
| |
(void)strcat(resolved, "/"); |
| |
(void)strcat(resolved, wbuf); |
| |
} |
| |
|
| |
/* Go back to where we came from. */ |
| |
if (fchdir(fd) < 0) { |
| |
serrno = errno; |
| |
goto err2; |
| |
} |
| |
|
| |
/* It's okay if the close fails, what's an fd more or less? */ |
| |
(void)close(fd); |
| |
return (resolved); |
| |
|
| |
err1: serrno = errno; |
| |
(void)fchdir(fd); |
| |
err2: (void)close(fd); |
| |
errno = serrno; |
| |
return (NULL); |
| |
} |
| |
|
| |
static char * |
| |
getcwd_physical(pt, size) |
| |
char *pt; |
| |
size_t size; |
| |
{ |
| register struct dirent *dp; |
register struct dirent *dp; |
| register DIR *dir; |
register DIR *dir; |
| register dev_t dev; |
register dev_t dev; |
|
| Line 244 getcwd(pt, size) |
|
| /* |
/* |
| * Allocate bytes (1024 - malloc space) for the string of "../"'s. |
* Allocate bytes (1024 - malloc space) for the string of "../"'s. |
| * Should always be enough (it's 340 levels). If it's not, allocate |
* Should always be enough (it's 340 levels). If it's not, allocate |
| * as necessary. Special * case the first stat, it's ".", not "..". |
* as necessary. Special case the first stat, it's ".", not "..". |
| */ |
*/ |
| if ((up = malloc(upsize = 1024 - 4)) == NULL) |
if ((up = malloc(upsize = 1024 - 4)) == NULL) |
| goto err; |
goto err; |