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 "testutil.h"
18 #include "apr_file_io.h"
19 #include "apr_file_info.h"
20 #include "apr_errno.h"
21 #include "apr_general.h"
22 #include "apr_pools.h"
23 #include "apr_lib.h"
24 #include "apr_strings.h"
25
26 #if defined(WIN32)
27 #include <direct.h>
28 #endif
29
30 #if defined(WIN32) || defined(OS2)
31 #define ABS_ROOT "C:/"
32 #elif defined(NETWARE)
33 #define ABS_ROOT "SYS:/"
34 #else
35 #define ABS_ROOT "/"
36 #endif
37
merge_aboveroot(abts_case * tc,void * data)38 static void merge_aboveroot(abts_case *tc, void *data)
39 {
40 apr_status_t rv;
41 char *dstpath = NULL;
42 char errmsg[256];
43
44 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo", ABS_ROOT"bar", APR_FILEPATH_NOTABOVEROOT,
45 p);
46 apr_strerror(rv, errmsg, sizeof(errmsg));
47 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EABOVEROOT(rv));
48 ABTS_PTR_EQUAL(tc, NULL, dstpath);
49 ABTS_STR_EQUAL(tc, "The given path was above the root path", errmsg);
50 }
51
merge_belowroot(abts_case * tc,void * data)52 static void merge_belowroot(abts_case *tc, void *data)
53 {
54 apr_status_t rv;
55 char *dstpath = NULL;
56
57 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo", ABS_ROOT"foo/bar",
58 APR_FILEPATH_NOTABOVEROOT, p);
59 ABTS_PTR_NOTNULL(tc, dstpath);
60 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
61 ABTS_STR_EQUAL(tc, ABS_ROOT"foo/bar", dstpath);
62 }
63
merge_noflag(abts_case * tc,void * data)64 static void merge_noflag(abts_case *tc, void *data)
65 {
66 apr_status_t rv;
67 char *dstpath = NULL;
68
69 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo", ABS_ROOT"foo/bar", 0, p);
70 ABTS_PTR_NOTNULL(tc, dstpath);
71 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
72 ABTS_STR_EQUAL(tc, ABS_ROOT"foo/bar", dstpath);
73 }
74
merge_dotdot(abts_case * tc,void * data)75 static void merge_dotdot(abts_case *tc, void *data)
76 {
77 apr_status_t rv;
78 char *dstpath = NULL;
79
80 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../baz", 0, p);
81 ABTS_PTR_NOTNULL(tc, dstpath);
82 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
83 ABTS_STR_EQUAL(tc, ABS_ROOT"foo/baz", dstpath);
84
85 rv = apr_filepath_merge(&dstpath, "", "../test", 0, p);
86 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
87 ABTS_STR_EQUAL(tc, "../test", dstpath);
88
89 /* Very dangerous assumptions here about what the cwd is. However, let's assume
90 * that the testall is invoked from within apr/test/ so the following test should
91 * return ../test unless a previously fixed bug remains or the developer changes
92 * the case of the test directory:
93 */
94 rv = apr_filepath_merge(&dstpath, "", "../test", APR_FILEPATH_TRUENAME, p);
95 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
96 ABTS_STR_EQUAL(tc, "../test", dstpath);
97 }
98
merge_dotdot_dotdot_dotdot(abts_case * tc,void * data)99 static void merge_dotdot_dotdot_dotdot(abts_case *tc, void *data)
100 {
101 apr_status_t rv;
102 char *dstpath = NULL;
103
104 rv = apr_filepath_merge(&dstpath, "",
105 "../../..", APR_FILEPATH_TRUENAME, p);
106 ABTS_PTR_NOTNULL(tc, dstpath);
107 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
108 ABTS_STR_EQUAL(tc, "../../..", dstpath);
109
110 rv = apr_filepath_merge(&dstpath, "",
111 "../../../", APR_FILEPATH_TRUENAME, p);
112 ABTS_PTR_NOTNULL(tc, dstpath);
113 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
114 ABTS_STR_EQUAL(tc, "../../../", dstpath);
115 }
116
merge_secure(abts_case * tc,void * data)117 static void merge_secure(abts_case *tc, void *data)
118 {
119 apr_status_t rv;
120 char *dstpath = NULL;
121
122 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../bar/baz", 0, p);
123 ABTS_PTR_NOTNULL(tc, dstpath);
124 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
125 ABTS_STR_EQUAL(tc, ABS_ROOT"foo/bar/baz", dstpath);
126 }
127
merge_notrel(abts_case * tc,void * data)128 static void merge_notrel(abts_case *tc, void *data)
129 {
130 apr_status_t rv;
131 char *dstpath = NULL;
132
133 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../baz",
134 APR_FILEPATH_NOTRELATIVE, p);
135 ABTS_PTR_NOTNULL(tc, dstpath);
136 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
137 ABTS_STR_EQUAL(tc, ABS_ROOT"foo/baz", dstpath);
138 }
139
merge_notrelfail(abts_case * tc,void * data)140 static void merge_notrelfail(abts_case *tc, void *data)
141 {
142 apr_status_t rv;
143 char *dstpath = NULL;
144 char errmsg[256];
145
146 rv = apr_filepath_merge(&dstpath, "foo/bar", "../baz",
147 APR_FILEPATH_NOTRELATIVE, p);
148 apr_strerror(rv, errmsg, sizeof(errmsg));
149
150 ABTS_PTR_EQUAL(tc, NULL, dstpath);
151 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ERELATIVE(rv));
152 ABTS_STR_EQUAL(tc, "The given path is relative", errmsg);
153 }
154
merge_notabsfail(abts_case * tc,void * data)155 static void merge_notabsfail(abts_case *tc, void *data)
156 {
157 apr_status_t rv;
158 char *dstpath = NULL;
159 char errmsg[256];
160
161 rv = apr_filepath_merge(&dstpath, ABS_ROOT"foo/bar", "../baz",
162 APR_FILEPATH_NOTABSOLUTE, p);
163 apr_strerror(rv, errmsg, sizeof(errmsg));
164
165 ABTS_PTR_EQUAL(tc, NULL, dstpath);
166 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_EABSOLUTE(rv));
167 ABTS_STR_EQUAL(tc, "The given path is absolute", errmsg);
168 }
169
merge_notabs(abts_case * tc,void * data)170 static void merge_notabs(abts_case *tc, void *data)
171 {
172 apr_status_t rv;
173 char *dstpath = NULL;
174
175 rv = apr_filepath_merge(&dstpath, "foo/bar", "../baz",
176 APR_FILEPATH_NOTABSOLUTE, p);
177
178 ABTS_PTR_NOTNULL(tc, dstpath);
179 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
180 ABTS_STR_EQUAL(tc, "foo/baz", dstpath);
181 }
182
183 #if defined (WIN32)
merge_lowercasedrive(abts_case * tc,void * data)184 static void merge_lowercasedrive(abts_case *tc, void *data)
185 {
186 char current_dir[1024];
187 char current_dir_on_C[1024];
188 char *dir_on_c;
189 char *testdir;
190 apr_status_t rv;
191
192 /* Change the current directory on C: from something like "C:\dir"
193 to something like "c:\dir" to replicate the failing case. */
194 ABTS_PTR_NOTNULL(tc, _getcwd(current_dir, sizeof(current_dir)));
195
196 /* 3 stands for drive C: */
197 ABTS_PTR_NOTNULL(tc, _getdcwd(3, current_dir_on_C,
198 sizeof(current_dir_on_C)));
199
200 /* Use the same path, but now with a lower case driveletter */
201 dir_on_c = apr_pstrdup(p, current_dir_on_C);
202 dir_on_c[0] = (char)tolower(dir_on_c[0]);
203
204 chdir(dir_on_c);
205
206 /* Now merge a drive relative path with an upper case drive letter. */
207 rv = apr_filepath_merge(&testdir, NULL, "C:hi",
208 APR_FILEPATH_NOTRELATIVE, p);
209
210 /* Change back to original directory for next tests */
211 chdir("C:\\"); /* Switch to upper case */
212 chdir(current_dir_on_C); /* Switch cwd on C: */
213 chdir(current_dir); /* Switch back to original cwd */
214
215 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
216 }
217 #endif
218
root_absolute(abts_case * tc,void * data)219 static void root_absolute(abts_case *tc, void *data)
220 {
221 apr_status_t rv;
222 const char *root = NULL;
223 const char *path = ABS_ROOT"foo/bar";
224
225 rv = apr_filepath_root(&root, &path, 0, p);
226
227 ABTS_PTR_NOTNULL(tc, root);
228 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
229 ABTS_STR_EQUAL(tc, ABS_ROOT, root);
230 }
231
root_relative(abts_case * tc,void * data)232 static void root_relative(abts_case *tc, void *data)
233 {
234 apr_status_t rv;
235 const char *root = NULL;
236 const char *path = "foo/bar";
237 char errmsg[256];
238
239 rv = apr_filepath_root(&root, &path, 0, p);
240 apr_strerror(rv, errmsg, sizeof(errmsg));
241
242 ABTS_PTR_EQUAL(tc, NULL, root);
243 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ERELATIVE(rv));
244 ABTS_STR_EQUAL(tc, "The given path is relative", errmsg);
245 }
246
root_from_slash(abts_case * tc,void * data)247 static void root_from_slash(abts_case *tc, void *data)
248 {
249 apr_status_t rv;
250 const char *root = NULL;
251 const char *path = "//";
252
253 rv = apr_filepath_root(&root, &path, APR_FILEPATH_TRUENAME, p);
254
255 #if defined(WIN32) || defined(OS2)
256 ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv);
257 ABTS_STR_EQUAL(tc, "//", root);
258 #else
259 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
260 ABTS_STR_EQUAL(tc, "/", root);
261 #endif
262 ABTS_STR_EQUAL(tc, "", path);
263 }
264
root_from_cwd_and_back(abts_case * tc,void * data)265 static void root_from_cwd_and_back(abts_case *tc, void *data)
266 {
267 apr_status_t rv;
268 const char *root = NULL;
269 const char *path = "//";
270 char *origpath;
271 char *testpath;
272 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
273 int hadfailed;
274 #endif
275
276 ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_filepath_get(&origpath, 0, p));
277 path = origpath;
278 rv = apr_filepath_root(&root, &path, APR_FILEPATH_TRUENAME, p);
279
280 #if defined(WIN32) || defined(OS2)
281 hadfailed = tc->failed;
282 /* It appears some mingw/cygwin and more modern builds can return
283 * a lowercase drive designation, but we canonicalize to uppercase
284 */
285 ABTS_INT_EQUAL(tc, toupper(origpath[0]), root[0]);
286 ABTS_INT_EQUAL(tc, ':', root[1]);
287 ABTS_INT_EQUAL(tc, '/', root[2]);
288 ABTS_INT_EQUAL(tc, 0, root[3]);
289 ABTS_STR_EQUAL(tc, origpath + 3, path);
290 #elif defined(NETWARE)
291 ABTS_INT_EQUAL(tc, origpath[0], root[0]);
292 {
293 char *pt = strchr(root, ':');
294 ABTS_PTR_NOTNULL(tc, pt);
295 ABTS_INT_EQUAL(tc, ':', pt[0]);
296 ABTS_INT_EQUAL(tc, '/', pt[1]);
297 ABTS_INT_EQUAL(tc, 0, pt[2]);
298 pt = strchr(origpath, ':');
299 ABTS_PTR_NOTNULL(tc, pt);
300 ABTS_STR_EQUAL(tc, (pt+2), path);
301 }
302 #else
303 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
304 ABTS_STR_EQUAL(tc, "/", root);
305 ABTS_STR_EQUAL(tc, origpath + 1, path);
306 #endif
307
308 rv = apr_filepath_merge(&testpath, root, path,
309 APR_FILEPATH_TRUENAME
310 | APR_FILEPATH_NOTABOVEROOT
311 | APR_FILEPATH_NOTRELATIVE, p);
312 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
313 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
314 hadfailed = tc->failed;
315 #endif
316 /* The API doesn't promise equality!!!
317 * apr_filepath_get never promised a canonical filepath.
318 * We'll emit noise under verbose so the user is aware,
319 * but translate this back to success.
320 */
321 ABTS_STR_EQUAL(tc, origpath, testpath);
322 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
323 if (!hadfailed) tc->failed = 0;
324 #endif
325 }
326
327
testnames(abts_suite * suite)328 abts_suite *testnames(abts_suite *suite)
329 {
330 suite = ADD_SUITE(suite)
331
332 abts_run_test(suite, merge_aboveroot, NULL);
333 abts_run_test(suite, merge_belowroot, NULL);
334 abts_run_test(suite, merge_noflag, NULL);
335 abts_run_test(suite, merge_dotdot, NULL);
336 abts_run_test(suite, merge_secure, NULL);
337 abts_run_test(suite, merge_notrel, NULL);
338 abts_run_test(suite, merge_notrelfail, NULL);
339 abts_run_test(suite, merge_notabs, NULL);
340 abts_run_test(suite, merge_notabsfail, NULL);
341 abts_run_test(suite, merge_dotdot_dotdot_dotdot, NULL);
342 #if defined(WIN32)
343 abts_run_test(suite, merge_lowercasedrive, NULL);
344 #endif
345
346 abts_run_test(suite, root_absolute, NULL);
347 abts_run_test(suite, root_relative, NULL);
348 abts_run_test(suite, root_from_slash, NULL);
349 abts_run_test(suite, root_from_cwd_and_back, NULL);
350
351 return suite;
352 }
353
354