diff options
Diffstat (limited to 'openbsd-compat/realpath.c')
-rw-r--r-- | openbsd-compat/realpath.c | 69 |
1 files changed, 51 insertions, 18 deletions
diff --git a/openbsd-compat/realpath.c b/openbsd-compat/realpath.c index 218fbecb2..7f73bd998 100644 --- a/openbsd-compat/realpath.c +++ b/openbsd-compat/realpath.c | |||
@@ -37,7 +37,7 @@ | |||
37 | #if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) | 37 | #if !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) |
38 | 38 | ||
39 | #if defined(LIBC_SCCS) && !defined(lint) | 39 | #if defined(LIBC_SCCS) && !defined(lint) |
40 | static char *rcsid = "$OpenBSD: realpath.c,v 1.10 2003/08/01 21:04:59 millert Exp $"; | 40 | static char *rcsid = "$OpenBSD: realpath.c,v 1.11 2004/11/30 15:12:59 millert Exp $"; |
41 | #endif /* LIBC_SCCS and not lint */ | 41 | #endif /* LIBC_SCCS and not lint */ |
42 | 42 | ||
43 | #include <sys/param.h> | 43 | #include <sys/param.h> |
@@ -67,17 +67,25 @@ char * | |||
67 | realpath(const char *path, char *resolved) | 67 | realpath(const char *path, char *resolved) |
68 | { | 68 | { |
69 | struct stat sb; | 69 | struct stat sb; |
70 | int fd, n, needslash, serrno = 0; | 70 | int fd, n, needslash, serrno; |
71 | char *p, *q, wbuf[MAXPATHLEN], start[MAXPATHLEN]; | 71 | char *p, *q, wbuf[MAXPATHLEN]; |
72 | int symlinks = 0; | 72 | int symlinks = 0; |
73 | 73 | ||
74 | /* Save the starting point. */ | 74 | /* Save the starting point. */ |
75 | getcwd(start,MAXPATHLEN); | 75 | #ifndef HAVE_FCHDIR |
76 | char start[MAXPATHLEN]; | ||
77 | /* this is potentially racy but without fchdir we have no option */ | ||
78 | if (getcwd(start, sizeof(start)) == NULL) { | ||
79 | resolved[0] = '.'; | ||
80 | resolved[1] = '\0'; | ||
81 | return (NULL); | ||
82 | } | ||
83 | #endif | ||
76 | if ((fd = open(".", O_RDONLY)) < 0) { | 84 | if ((fd = open(".", O_RDONLY)) < 0) { |
77 | (void)strlcpy(resolved, ".", MAXPATHLEN); | 85 | resolved[0] = '.'; |
86 | resolved[1] = '\0'; | ||
78 | return (NULL); | 87 | return (NULL); |
79 | } | 88 | } |
80 | close(fd); | ||
81 | 89 | ||
82 | /* Convert "." -> "" to optimize away a needless lstat() and chdir() */ | 90 | /* Convert "." -> "" to optimize away a needless lstat() and chdir() */ |
83 | if (path[0] == '.' && path[1] == '\0') | 91 | if (path[0] == '.' && path[1] == '\0') |
@@ -91,7 +99,10 @@ realpath(const char *path, char *resolved) | |||
91 | * if it is a directory, then change to that directory. | 99 | * if it is a directory, then change to that directory. |
92 | * get the current directory name and append the basename. | 100 | * get the current directory name and append the basename. |
93 | */ | 101 | */ |
94 | strlcpy(resolved, path, MAXPATHLEN); | 102 | if (strlcpy(resolved, path, MAXPATHLEN) >= MAXPATHLEN) { |
103 | serrno = ENAMETOOLONG; | ||
104 | goto err2; | ||
105 | } | ||
95 | loop: | 106 | loop: |
96 | q = strrchr(resolved, '/'); | 107 | q = strrchr(resolved, '/'); |
97 | if (q != NULL) { | 108 | if (q != NULL) { |
@@ -114,11 +125,10 @@ loop: | |||
114 | if (*p != '\0' && lstat(p, &sb) == 0) { | 125 | if (*p != '\0' && lstat(p, &sb) == 0) { |
115 | if (S_ISLNK(sb.st_mode)) { | 126 | if (S_ISLNK(sb.st_mode)) { |
116 | if (++symlinks > MAXSYMLINKS) { | 127 | if (++symlinks > MAXSYMLINKS) { |
117 | serrno = ELOOP; | 128 | errno = ELOOP; |
118 | goto err1; | 129 | goto err1; |
119 | } | 130 | } |
120 | n = readlink(p, resolved, MAXPATHLEN-1); | 131 | if ((n = readlink(p, resolved, MAXPATHLEN-1)) < 0) |
121 | if (n < 0) | ||
122 | goto err1; | 132 | goto err1; |
123 | resolved[n] = '\0'; | 133 | resolved[n] = '\0'; |
124 | goto loop; | 134 | goto loop; |
@@ -134,8 +144,11 @@ loop: | |||
134 | * Save the last component name and get the full pathname of | 144 | * Save the last component name and get the full pathname of |
135 | * the current directory. | 145 | * the current directory. |
136 | */ | 146 | */ |
137 | (void)strlcpy(wbuf, p, sizeof wbuf); | 147 | if (strlcpy(wbuf, p, sizeof(wbuf)) >= sizeof(wbuf)) { |
138 | if (getcwd(resolved, MAXPATHLEN) == 0) | 148 | errno = ENAMETOOLONG; |
149 | goto err1; | ||
150 | } | ||
151 | if (getcwd(resolved, MAXPATHLEN) == NULL) | ||
139 | goto err1; | 152 | goto err1; |
140 | 153 | ||
141 | /* | 154 | /* |
@@ -149,23 +162,43 @@ loop: | |||
149 | 162 | ||
150 | if (*wbuf) { | 163 | if (*wbuf) { |
151 | if (strlen(resolved) + strlen(wbuf) + needslash >= MAXPATHLEN) { | 164 | if (strlen(resolved) + strlen(wbuf) + needslash >= MAXPATHLEN) { |
152 | serrno = ENAMETOOLONG; | 165 | errno = ENAMETOOLONG; |
166 | goto err1; | ||
167 | } | ||
168 | if (needslash) { | ||
169 | if (strlcat(resolved, "/", MAXPATHLEN) >= MAXPATHLEN) { | ||
170 | errno = ENAMETOOLONG; | ||
171 | goto err1; | ||
172 | } | ||
173 | } | ||
174 | if (strlcat(resolved, wbuf, MAXPATHLEN) >= MAXPATHLEN) { | ||
175 | errno = ENAMETOOLONG; | ||
153 | goto err1; | 176 | goto err1; |
154 | } | 177 | } |
155 | if (needslash) | ||
156 | strlcat(resolved, "/", MAXPATHLEN); | ||
157 | strlcat(resolved, wbuf, MAXPATHLEN); | ||
158 | } | 178 | } |
159 | 179 | ||
160 | /* Go back to where we came from. */ | 180 | /* Go back to where we came from. */ |
181 | #ifdef HAVE_FCHDIR | ||
182 | if (fchdir(fd) < 0) { | ||
183 | #else | ||
161 | if (chdir(start) < 0) { | 184 | if (chdir(start) < 0) { |
185 | #endif | ||
162 | serrno = errno; | 186 | serrno = errno; |
163 | goto err2; | 187 | goto err2; |
164 | } | 188 | } |
189 | |||
190 | /* It's okay if the close fails, what's an fd more or less? */ | ||
191 | (void)close(fd); | ||
165 | return (resolved); | 192 | return (resolved); |
166 | 193 | ||
167 | err1: chdir(start); | 194 | err1: serrno = errno; |
168 | err2: errno = serrno; | 195 | #ifdef HAVE_FCHDIR |
196 | (void)fchdir(fd); | ||
197 | #else | ||
198 | chdir(start); | ||
199 | #endif | ||
200 | err2: (void)close(fd); | ||
201 | errno = serrno; | ||
169 | return (NULL); | 202 | return (NULL); |
170 | } | 203 | } |
171 | #endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ | 204 | #endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ |