File: | libs/apr/file_io/unix/filepath.c |
Location: | line 138, column 18 |
Description: | Assigned value is garbage or undefined |
1 | /* Licensed to the Apache Software Foundation (ASF) under one or more | |||
2 | * contributor license agreements. See the NOTICE file distributed with | |||
3 | * this work for additional information regarding copyright ownership. | |||
4 | * The ASF licenses this file to You under the Apache License, Version 2.0 | |||
5 | * (the "License"); you may not use this file except in compliance with | |||
6 | * the License. You may obtain a copy of the License at | |||
7 | * | |||
8 | * http://www.apache.org/licenses/LICENSE-2.0 | |||
9 | * | |||
10 | * Unless required by applicable law or agreed to in writing, software | |||
11 | * distributed under the License is distributed on an "AS IS" BASIS, | |||
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |||
13 | * See the License for the specific language governing permissions and | |||
14 | * limitations under the License. | |||
15 | */ | |||
16 | ||||
17 | #include "apr.h" | |||
18 | #include "apr_private.h" | |||
19 | #include "apr_arch_file_io.h" | |||
20 | #include "apr_file_io.h" | |||
21 | #include "apr_strings.h" | |||
22 | #define APR_WANT_STRFUNC | |||
23 | #include "apr_want.h" | |||
24 | #if APR_HAVE_UNISTD_H1 | |||
25 | #include <unistd.h> | |||
26 | #endif | |||
27 | ||||
28 | /* Win32 malpropism that can go away once everyone believes this | |||
29 | * code is golden, and I'm not testing it anymore :-) | |||
30 | */ | |||
31 | #if APR_HAVE_DIRENT_H1 | |||
32 | #include <dirent.h> | |||
33 | #endif | |||
34 | ||||
35 | /* Any OS that requires/refuses trailing slashes should be dealt with here. | |||
36 | */ | |||
37 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_get(char **defpath, apr_int32_t flags, | |||
38 | apr_pool_t *p) | |||
39 | { | |||
40 | char path[APR_PATH_MAX4096]; | |||
41 | ||||
42 | if (!getcwd(path, sizeof(path))) { | |||
43 | if (errno(*__errno_location ()) == ERANGE34) | |||
44 | return APR_ENAMETOOLONG36; | |||
45 | else | |||
46 | return errno(*__errno_location ()); | |||
47 | } | |||
48 | *defpath = apr_pstrdup(p, path); | |||
49 | ||||
50 | return APR_SUCCESS0; | |||
51 | } | |||
52 | ||||
53 | ||||
54 | /* Any OS that requires/refuses trailing slashes should be dealt with here | |||
55 | */ | |||
56 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_set(const char *path, apr_pool_t *p) | |||
57 | { | |||
58 | if (chdir(path) != 0) | |||
59 | return errno(*__errno_location ()); | |||
60 | ||||
61 | return APR_SUCCESS0; | |||
62 | } | |||
63 | ||||
64 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_root(const char **rootpath, | |||
65 | const char **inpath, | |||
66 | apr_int32_t flags, | |||
67 | apr_pool_t *p) | |||
68 | { | |||
69 | if (**inpath == '/') { | |||
70 | *rootpath = apr_pstrdup(p, "/"); | |||
71 | do { | |||
72 | ++(*inpath); | |||
73 | } while (**inpath == '/'); | |||
74 | ||||
75 | return APR_SUCCESS0; | |||
76 | } | |||
77 | ||||
78 | return APR_ERELATIVE(20000 + 21); | |||
79 | } | |||
80 | ||||
81 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_merge(char **newpath, | |||
82 | const char *rootpath, | |||
83 | const char *addpath, | |||
84 | apr_int32_t flags, | |||
85 | apr_pool_t *p) | |||
86 | { | |||
87 | char *path; | |||
88 | apr_size_t rootlen; /* is the length of the src rootpath */ | |||
89 | apr_size_t maxlen; /* maximum total path length */ | |||
90 | apr_size_t keptlen; /* is the length of the retained rootpath */ | |||
91 | apr_size_t pathlen; /* is the length of the result path */ | |||
92 | apr_size_t seglen; /* is the end of the current segment */ | |||
93 | apr_status_t rv; | |||
94 | ||||
95 | /* Treat null as an empty path. | |||
96 | */ | |||
97 | if (!addpath) | |||
| ||||
98 | addpath = ""; | |||
99 | ||||
100 | if (addpath[0] == '/') { | |||
101 | /* If addpath is rooted, then rootpath is unused. | |||
102 | * Ths violates any APR_FILEPATH_SECUREROOTTEST and | |||
103 | * APR_FILEPATH_NOTABSOLUTE flags specified. | |||
104 | */ | |||
105 | if (flags & APR_FILEPATH_SECUREROOTTEST0x02) | |||
106 | return APR_EABOVEROOT(20000 + 23); | |||
107 | if (flags & APR_FILEPATH_NOTABSOLUTE0x08) | |||
108 | return APR_EABSOLUTE(20000 + 20); | |||
109 | ||||
110 | /* If APR_FILEPATH_NOTABOVEROOT wasn't specified, | |||
111 | * we won't test the root again, it's ignored. | |||
112 | * Waste no CPU retrieving the working path. | |||
113 | */ | |||
114 | if (!rootpath && !(flags & APR_FILEPATH_NOTABOVEROOT0x01)) | |||
115 | rootpath = ""; | |||
116 | } | |||
117 | else { | |||
118 | /* If APR_FILEPATH_NOTABSOLUTE is specified, the caller | |||
119 | * requires a relative result. If the rootpath is | |||
120 | * ommitted, we do not retrieve the working path, | |||
121 | * if rootpath was supplied as absolute then fail. | |||
122 | */ | |||
123 | if (flags & APR_FILEPATH_NOTABSOLUTE0x08) { | |||
124 | if (!rootpath) | |||
125 | rootpath = ""; | |||
126 | else if (rootpath[0] == '/') | |||
127 | return APR_EABSOLUTE(20000 + 20); | |||
128 | } | |||
129 | } | |||
130 | ||||
131 | if (!rootpath) { | |||
132 | /* Start with the current working path. This is bass akwards, | |||
133 | * but required since the compiler (at least vc) doesn't like | |||
134 | * passing the address of a char const* for a char** arg. | |||
135 | */ | |||
136 | char *getpath; | |||
137 | rv = apr_filepath_get(&getpath, flags, p); | |||
138 | rootpath = getpath; | |||
| ||||
139 | if (rv != APR_SUCCESS0) | |||
140 | return errno(*__errno_location ()); | |||
141 | ||||
142 | /* XXX: Any kernel subject to goofy, uncanonical results | |||
143 | * must run the rootpath against the user's given flags. | |||
144 | * Simplest would be a recursive call to apr_filepath_merge | |||
145 | * with an empty (not null) rootpath and addpath of the cwd. | |||
146 | */ | |||
147 | } | |||
148 | ||||
149 | rootlen = strlen(rootpath); | |||
150 | maxlen = rootlen + strlen(addpath) + 4; /* 4 for slashes at start, after | |||
151 | * root, and at end, plus trailing | |||
152 | * null */ | |||
153 | if (maxlen > APR_PATH_MAX4096) { | |||
154 | return APR_ENAMETOOLONG36; | |||
155 | } | |||
156 | path = (char *)apr_palloc(p, maxlen); | |||
157 | ||||
158 | if (addpath[0] == '/') { | |||
159 | /* Ignore the given root path, strip off leading | |||
160 | * '/'s to a single leading '/' from the addpath, | |||
161 | * and leave addpath at the first non-'/' character. | |||
162 | */ | |||
163 | keptlen = 0; | |||
164 | while (addpath[0] == '/') | |||
165 | ++addpath; | |||
166 | path[0] = '/'; | |||
167 | pathlen = 1; | |||
168 | } | |||
169 | else { | |||
170 | /* If both paths are relative, fail early | |||
171 | */ | |||
172 | if (rootpath[0] != '/' && (flags & APR_FILEPATH_NOTRELATIVE0x04)) | |||
173 | return APR_ERELATIVE(20000 + 21); | |||
174 | ||||
175 | /* Base the result path on the rootpath | |||
176 | */ | |||
177 | keptlen = rootlen; | |||
178 | memcpy(path, rootpath, rootlen); | |||
179 | ||||
180 | /* Always '/' terminate the given root path | |||
181 | */ | |||
182 | if (keptlen && path[keptlen - 1] != '/') { | |||
183 | path[keptlen++] = '/'; | |||
184 | } | |||
185 | pathlen = keptlen; | |||
186 | } | |||
187 | ||||
188 | while (*addpath) { | |||
189 | /* Parse each segment, find the closing '/' | |||
190 | */ | |||
191 | const char *next = addpath; | |||
192 | while (*next && (*next != '/')) { | |||
193 | ++next; | |||
194 | } | |||
195 | seglen = next - addpath; | |||
196 | ||||
197 | if (seglen == 0 || (seglen == 1 && addpath[0] == '.')) { | |||
198 | /* noop segment (/ or ./) so skip it | |||
199 | */ | |||
200 | } | |||
201 | else if (seglen == 2 && addpath[0] == '.' && addpath[1] == '.') { | |||
202 | /* backpath (../) */ | |||
203 | if (pathlen == 1 && path[0] == '/') { | |||
204 | /* Attempt to move above root. Always die if the | |||
205 | * APR_FILEPATH_SECUREROOTTEST flag is specified. | |||
206 | */ | |||
207 | if (flags & APR_FILEPATH_SECUREROOTTEST0x02) { | |||
208 | return APR_EABOVEROOT(20000 + 23); | |||
209 | } | |||
210 | ||||
211 | /* Otherwise this is simply a noop, above root is root. | |||
212 | * Flag that rootpath was entirely replaced. | |||
213 | */ | |||
214 | keptlen = 0; | |||
215 | } | |||
216 | else if (pathlen == 0 | |||
217 | || (pathlen == 3 | |||
218 | && !memcmp(path + pathlen - 3, "../", 3)) | |||
219 | || (pathlen > 3 | |||
220 | && !memcmp(path + pathlen - 4, "/../", 4))) { | |||
221 | /* Path is already backpathed or empty, if the | |||
222 | * APR_FILEPATH_SECUREROOTTEST.was given die now. | |||
223 | */ | |||
224 | if (flags & APR_FILEPATH_SECUREROOTTEST0x02) { | |||
225 | return APR_EABOVEROOT(20000 + 23); | |||
226 | } | |||
227 | ||||
228 | /* Otherwise append another backpath, including | |||
229 | * trailing slash if present. | |||
230 | */ | |||
231 | memcpy(path + pathlen, "../", *next ? 3 : 2); | |||
232 | pathlen += *next ? 3 : 2; | |||
233 | } | |||
234 | else { | |||
235 | /* otherwise crop the prior segment | |||
236 | */ | |||
237 | do { | |||
238 | --pathlen; | |||
239 | } while (pathlen && path[pathlen - 1] != '/'); | |||
240 | } | |||
241 | ||||
242 | /* Now test if we are above where we started and back up | |||
243 | * the keptlen offset to reflect the added/altered path. | |||
244 | */ | |||
245 | if (pathlen < keptlen) { | |||
246 | if (flags & APR_FILEPATH_SECUREROOTTEST0x02) { | |||
247 | return APR_EABOVEROOT(20000 + 23); | |||
248 | } | |||
249 | keptlen = pathlen; | |||
250 | } | |||
251 | } | |||
252 | else { | |||
253 | /* An actual segment, append it to the destination path | |||
254 | */ | |||
255 | if (*next) { | |||
256 | seglen++; | |||
257 | } | |||
258 | memcpy(path + pathlen, addpath, seglen); | |||
259 | pathlen += seglen; | |||
260 | } | |||
261 | ||||
262 | /* Skip over trailing slash to the next segment | |||
263 | */ | |||
264 | if (*next) { | |||
265 | ++next; | |||
266 | } | |||
267 | ||||
268 | addpath = next; | |||
269 | } | |||
270 | path[pathlen] = '\0'; | |||
271 | ||||
272 | /* keptlen will be the rootlen unless the addpath contained | |||
273 | * backpath elements. If so, and APR_FILEPATH_NOTABOVEROOT | |||
274 | * is specified (APR_FILEPATH_SECUREROOTTEST was caught above), | |||
275 | * compare the original root to assure the result path is | |||
276 | * still within given root path. | |||
277 | */ | |||
278 | if ((flags & APR_FILEPATH_NOTABOVEROOT0x01) && keptlen < rootlen) { | |||
279 | if (strncmp(rootpath, path, rootlen)(__extension__ (__builtin_constant_p (rootlen) && ((__builtin_constant_p (rootpath) && strlen (rootpath) < ((size_t) (rootlen ))) || (__builtin_constant_p (path) && strlen (path) < ((size_t) (rootlen)))) ? __extension__ ({ size_t __s1_len, __s2_len ; (__builtin_constant_p (rootpath) && __builtin_constant_p (path) && (__s1_len = __builtin_strlen (rootpath), __s2_len = __builtin_strlen (path), (!((size_t)(const void *)((rootpath ) + 1) - (size_t)(const void *)(rootpath) == 1) || __s1_len >= 4) && (!((size_t)(const void *)((path) + 1) - (size_t )(const void *)(path) == 1) || __s2_len >= 4)) ? __builtin_strcmp (rootpath, path) : (__builtin_constant_p (rootpath) && ((size_t)(const void *)((rootpath) + 1) - (size_t)(const void *)(rootpath) == 1) && (__s1_len = __builtin_strlen ( rootpath), __s1_len < 4) ? (__builtin_constant_p (path) && ((size_t)(const void *)((path) + 1) - (size_t)(const void *) (path) == 1) ? __builtin_strcmp (rootpath, path) : (__extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (path); int __result = (((const unsigned char *) (const char *) (rootpath))[0] - __s2[0]); if (__s1_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (rootpath))[1] - __s2[1]); if (__s1_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (rootpath))[2] - __s2[2]); if (__s1_len > 2 && __result == 0) __result = (((const unsigned char *) (const char *) (rootpath))[3] - __s2[3]); } } __result; }))) : (__builtin_constant_p (path) && ((size_t)(const void *)((path) + 1) - (size_t )(const void *)(path) == 1) && (__s2_len = __builtin_strlen (path), __s2_len < 4) ? (__builtin_constant_p (rootpath) && ((size_t)(const void *)((rootpath) + 1) - (size_t)(const void *)(rootpath) == 1) ? __builtin_strcmp (rootpath, path) : (- ( __extension__ ({ const unsigned char *__s2 = (const unsigned char *) (const char *) (rootpath); int __result = (((const unsigned char *) (const char *) (path))[0] - __s2[0]); if (__s2_len > 0 && __result == 0) { __result = (((const unsigned char *) (const char *) (path))[1] - __s2[1]); if (__s2_len > 1 && __result == 0) { __result = (((const unsigned char *) (const char *) (path))[2] - __s2[2]); if (__s2_len > 2 && __result == 0) __result = (((const unsigned char * ) (const char *) (path))[3] - __s2[3]); } } __result; })))) : __builtin_strcmp (rootpath, path)))); }) : strncmp (rootpath , path, rootlen)))) { | |||
280 | return APR_EABOVEROOT(20000 + 23); | |||
281 | } | |||
282 | if (rootpath[rootlen - 1] != '/' | |||
283 | && path[rootlen] && path[rootlen] != '/') { | |||
284 | return APR_EABOVEROOT(20000 + 23); | |||
285 | } | |||
286 | } | |||
287 | ||||
288 | *newpath = path; | |||
289 | return APR_SUCCESS0; | |||
290 | } | |||
291 | ||||
292 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_list_split(apr_array_header_t **pathelts, | |||
293 | const char *liststr, | |||
294 | apr_pool_t *p) | |||
295 | { | |||
296 | return apr_filepath_list_split_impl(pathelts, liststr, ':', p); | |||
297 | } | |||
298 | ||||
299 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_list_merge(char **liststr, | |||
300 | apr_array_header_t *pathelts, | |||
301 | apr_pool_t *p) | |||
302 | { | |||
303 | return apr_filepath_list_merge_impl(liststr, pathelts, ':', p); | |||
304 | } | |||
305 | ||||
306 | APR_DECLARE(apr_status_t)apr_status_t apr_filepath_encoding(int *style, apr_pool_t *p) | |||
307 | { | |||
308 | *style = APR_FILEPATH_ENCODING_LOCALE1; | |||
309 | return APR_SUCCESS0; | |||
310 | } |