diff options
Diffstat (limited to 'openbsd-compat/realpath.c')
-rw-r--r-- | openbsd-compat/realpath.c | 61 |
1 files changed, 45 insertions, 16 deletions
diff --git a/openbsd-compat/realpath.c b/openbsd-compat/realpath.c index ba4cea938..a2f090e55 100644 --- a/openbsd-compat/realpath.c +++ b/openbsd-compat/realpath.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: realpath.c,v 1.13 2005/08/08 08:05:37 espie Exp $ */ | 1 | /* $OpenBSD: realpath.c,v 1.20 2015/10/13 20:55:37 millert Exp $ */ |
2 | /* | 2 | /* |
3 | * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> | 3 | * Copyright (c) 2003 Constantin S. Svintsoff <kostik@iclub.nsu.ru> |
4 | * | 4 | * |
@@ -42,6 +42,13 @@ | |||
42 | #include <stddef.h> | 42 | #include <stddef.h> |
43 | #include <string.h> | 43 | #include <string.h> |
44 | #include <unistd.h> | 44 | #include <unistd.h> |
45 | #include <limits.h> | ||
46 | |||
47 | #ifndef SYMLOOP_MAX | ||
48 | # define SYMLOOP_MAX 32 | ||
49 | #endif | ||
50 | |||
51 | /* A slightly modified copy of this file exists in libexec/ld.so */ | ||
45 | 52 | ||
46 | /* | 53 | /* |
47 | * char *realpath(const char *path, char resolved[PATH_MAX]); | 54 | * char *realpath(const char *path, char resolved[PATH_MAX]); |
@@ -51,16 +58,30 @@ | |||
51 | * in which case the path which caused trouble is left in (resolved). | 58 | * in which case the path which caused trouble is left in (resolved). |
52 | */ | 59 | */ |
53 | char * | 60 | char * |
54 | realpath(const char *path, char resolved[PATH_MAX]) | 61 | realpath(const char *path, char *resolved) |
55 | { | 62 | { |
56 | struct stat sb; | 63 | struct stat sb; |
57 | char *p, *q, *s; | 64 | char *p, *q, *s; |
58 | size_t left_len, resolved_len; | 65 | size_t left_len, resolved_len; |
59 | unsigned symlinks; | 66 | unsigned symlinks; |
60 | int serrno, slen; | 67 | int serrno, slen, mem_allocated; |
61 | char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; | 68 | char left[PATH_MAX], next_token[PATH_MAX], symlink[PATH_MAX]; |
62 | 69 | ||
70 | if (path[0] == '\0') { | ||
71 | errno = ENOENT; | ||
72 | return (NULL); | ||
73 | } | ||
74 | |||
63 | serrno = errno; | 75 | serrno = errno; |
76 | |||
77 | if (resolved == NULL) { | ||
78 | resolved = malloc(PATH_MAX); | ||
79 | if (resolved == NULL) | ||
80 | return (NULL); | ||
81 | mem_allocated = 1; | ||
82 | } else | ||
83 | mem_allocated = 0; | ||
84 | |||
64 | symlinks = 0; | 85 | symlinks = 0; |
65 | if (path[0] == '/') { | 86 | if (path[0] == '/') { |
66 | resolved[0] = '/'; | 87 | resolved[0] = '/'; |
@@ -71,7 +92,10 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
71 | left_len = strlcpy(left, path + 1, sizeof(left)); | 92 | left_len = strlcpy(left, path + 1, sizeof(left)); |
72 | } else { | 93 | } else { |
73 | if (getcwd(resolved, PATH_MAX) == NULL) { | 94 | if (getcwd(resolved, PATH_MAX) == NULL) { |
74 | strlcpy(resolved, ".", PATH_MAX); | 95 | if (mem_allocated) |
96 | free(resolved); | ||
97 | else | ||
98 | strlcpy(resolved, ".", PATH_MAX); | ||
75 | return (NULL); | 99 | return (NULL); |
76 | } | 100 | } |
77 | resolved_len = strlen(resolved); | 101 | resolved_len = strlen(resolved); |
@@ -79,7 +103,7 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
79 | } | 103 | } |
80 | if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { | 104 | if (left_len >= sizeof(left) || resolved_len >= PATH_MAX) { |
81 | errno = ENAMETOOLONG; | 105 | errno = ENAMETOOLONG; |
82 | return (NULL); | 106 | goto err; |
83 | } | 107 | } |
84 | 108 | ||
85 | /* | 109 | /* |
@@ -94,7 +118,7 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
94 | s = p ? p : left + left_len; | 118 | s = p ? p : left + left_len; |
95 | if (s - left >= (ptrdiff_t)sizeof(next_token)) { | 119 | if (s - left >= (ptrdiff_t)sizeof(next_token)) { |
96 | errno = ENAMETOOLONG; | 120 | errno = ENAMETOOLONG; |
97 | return (NULL); | 121 | goto err; |
98 | } | 122 | } |
99 | memcpy(next_token, left, s - left); | 123 | memcpy(next_token, left, s - left); |
100 | next_token[s - left] = '\0'; | 124 | next_token[s - left] = '\0'; |
@@ -104,7 +128,7 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
104 | if (resolved[resolved_len - 1] != '/') { | 128 | if (resolved[resolved_len - 1] != '/') { |
105 | if (resolved_len + 1 >= PATH_MAX) { | 129 | if (resolved_len + 1 >= PATH_MAX) { |
106 | errno = ENAMETOOLONG; | 130 | errno = ENAMETOOLONG; |
107 | return (NULL); | 131 | goto err; |
108 | } | 132 | } |
109 | resolved[resolved_len++] = '/'; | 133 | resolved[resolved_len++] = '/'; |
110 | resolved[resolved_len] = '\0'; | 134 | resolved[resolved_len] = '\0'; |
@@ -135,23 +159,23 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
135 | resolved_len = strlcat(resolved, next_token, PATH_MAX); | 159 | resolved_len = strlcat(resolved, next_token, PATH_MAX); |
136 | if (resolved_len >= PATH_MAX) { | 160 | if (resolved_len >= PATH_MAX) { |
137 | errno = ENAMETOOLONG; | 161 | errno = ENAMETOOLONG; |
138 | return (NULL); | 162 | goto err; |
139 | } | 163 | } |
140 | if (lstat(resolved, &sb) != 0) { | 164 | if (lstat(resolved, &sb) != 0) { |
141 | if (errno == ENOENT && p == NULL) { | 165 | if (errno == ENOENT && p == NULL) { |
142 | errno = serrno; | 166 | errno = serrno; |
143 | return (resolved); | 167 | return (resolved); |
144 | } | 168 | } |
145 | return (NULL); | 169 | goto err; |
146 | } | 170 | } |
147 | if (S_ISLNK(sb.st_mode)) { | 171 | if (S_ISLNK(sb.st_mode)) { |
148 | if (symlinks++ > MAXSYMLINKS) { | 172 | if (symlinks++ > SYMLOOP_MAX) { |
149 | errno = ELOOP; | 173 | errno = ELOOP; |
150 | return (NULL); | 174 | goto err; |
151 | } | 175 | } |
152 | slen = readlink(resolved, symlink, sizeof(symlink) - 1); | 176 | slen = readlink(resolved, symlink, sizeof(symlink) - 1); |
153 | if (slen < 0) | 177 | if (slen < 0) |
154 | return (NULL); | 178 | goto err; |
155 | symlink[slen] = '\0'; | 179 | symlink[slen] = '\0'; |
156 | if (symlink[0] == '/') { | 180 | if (symlink[0] == '/') { |
157 | resolved[1] = 0; | 181 | resolved[1] = 0; |
@@ -174,15 +198,15 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
174 | if (slen + 1 >= | 198 | if (slen + 1 >= |
175 | (ptrdiff_t)sizeof(symlink)) { | 199 | (ptrdiff_t)sizeof(symlink)) { |
176 | errno = ENAMETOOLONG; | 200 | errno = ENAMETOOLONG; |
177 | return (NULL); | 201 | goto err; |
178 | } | 202 | } |
179 | symlink[slen] = '/'; | 203 | symlink[slen] = '/'; |
180 | symlink[slen + 1] = 0; | 204 | symlink[slen + 1] = 0; |
181 | } | 205 | } |
182 | left_len = strlcat(symlink, left, sizeof(left)); | 206 | left_len = strlcat(symlink, left, sizeof(symlink)); |
183 | if (left_len >= sizeof(left)) { | 207 | if (left_len >= sizeof(symlink)) { |
184 | errno = ENAMETOOLONG; | 208 | errno = ENAMETOOLONG; |
185 | return (NULL); | 209 | goto err; |
186 | } | 210 | } |
187 | } | 211 | } |
188 | left_len = strlcpy(left, symlink, sizeof(left)); | 212 | left_len = strlcpy(left, symlink, sizeof(left)); |
@@ -196,5 +220,10 @@ realpath(const char *path, char resolved[PATH_MAX]) | |||
196 | if (resolved_len > 1 && resolved[resolved_len - 1] == '/') | 220 | if (resolved_len > 1 && resolved[resolved_len - 1] == '/') |
197 | resolved[resolved_len - 1] = '\0'; | 221 | resolved[resolved_len - 1] = '\0'; |
198 | return (resolved); | 222 | return (resolved); |
223 | |||
224 | err: | ||
225 | if (mem_allocated) | ||
226 | free(resolved); | ||
227 | return (NULL); | ||
199 | } | 228 | } |
200 | #endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ | 229 | #endif /* !defined(HAVE_REALPATH) || defined(BROKEN_REALPATH) */ |