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
merge_shortname(abts_case * tc,void * data)218 static void merge_shortname(abts_case *tc, void *data)
219 {
220 apr_status_t rv;
221 char *long_path;
222 char short_path[MAX_PATH+1];
223 DWORD short_len;
224 char *result_path;
225
226 /* 'A b.c' is not a valid short path, so will have multiple representations
227 when short path name generation is enabled... but its 'short' path will
228 most likely be longer than the long path */
229 rv = apr_dir_make_recursive("C:/data/short/A b.c",
230 APR_UREAD | APR_UWRITE | APR_UEXECUTE, p);
231 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
232
233 rv = apr_filepath_merge(&long_path, NULL, "C:/data/short/A b.c",
234 APR_FILEPATH_NOTRELATIVE, p);
235 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
236
237 short_len = GetShortPathName(long_path, short_path, sizeof(short_path));
238 if (short_len > MAX_PATH)
239 return; /* Unable to test. Impossible shortname */
240
241 if (! strcmp(long_path, short_path))
242 return; /* Unable to test. 8dot3name option is probably not enabled */
243
244 rv = apr_filepath_merge(&result_path, "", short_path, APR_FILEPATH_TRUENAME,
245 p);
246 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
247
248 ABTS_STR_EQUAL(tc, long_path, result_path);
249 }
250 #endif
251
root_absolute(abts_case * tc,void * data)252 static void root_absolute(abts_case *tc, void *data)
253 {
254 apr_status_t rv;
255 const char *root = NULL;
256 const char *path = ABS_ROOT"foo/bar";
257
258 rv = apr_filepath_root(&root, &path, 0, p);
259
260 ABTS_PTR_NOTNULL(tc, root);
261 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
262 ABTS_STR_EQUAL(tc, ABS_ROOT, root);
263 }
264
root_relative(abts_case * tc,void * data)265 static void root_relative(abts_case *tc, void *data)
266 {
267 apr_status_t rv;
268 const char *root = NULL;
269 const char *path = "foo/bar";
270 char errmsg[256];
271
272 rv = apr_filepath_root(&root, &path, 0, p);
273 apr_strerror(rv, errmsg, sizeof(errmsg));
274
275 ABTS_PTR_EQUAL(tc, NULL, root);
276 ABTS_INT_EQUAL(tc, 1, APR_STATUS_IS_ERELATIVE(rv));
277 ABTS_STR_EQUAL(tc, "The given path is relative", errmsg);
278 }
279
root_from_slash(abts_case * tc,void * data)280 static void root_from_slash(abts_case *tc, void *data)
281 {
282 apr_status_t rv;
283 const char *root = NULL;
284 const char *path = "//";
285
286 rv = apr_filepath_root(&root, &path, APR_FILEPATH_TRUENAME, p);
287
288 #if defined(WIN32) || defined(OS2)
289 ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv);
290 ABTS_STR_EQUAL(tc, "//", root);
291 #else
292 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
293 ABTS_STR_EQUAL(tc, "/", root);
294 #endif
295 ABTS_STR_EQUAL(tc, "", path);
296 }
297
root_from_cwd_and_back(abts_case * tc,void * data)298 static void root_from_cwd_and_back(abts_case *tc, void *data)
299 {
300 apr_status_t rv;
301 const char *root = NULL;
302 const char *path = "//";
303 char *origpath;
304 char *testpath;
305 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
306 int hadfailed;
307 #endif
308
309 ABTS_INT_EQUAL(tc, APR_SUCCESS, apr_filepath_get(&origpath, 0, p));
310 path = origpath;
311 rv = apr_filepath_root(&root, &path, APR_FILEPATH_TRUENAME, p);
312
313 #if defined(WIN32) || defined(OS2)
314 hadfailed = tc->failed;
315 /* It appears some mingw/cygwin and more modern builds can return
316 * a lowercase drive designation, but we canonicalize to uppercase
317 */
318 ABTS_INT_EQUAL(tc, toupper(origpath[0]), root[0]);
319 ABTS_INT_EQUAL(tc, ':', root[1]);
320 ABTS_INT_EQUAL(tc, '/', root[2]);
321 ABTS_INT_EQUAL(tc, 0, root[3]);
322 ABTS_STR_EQUAL(tc, origpath + 3, path);
323 #elif defined(NETWARE)
324 ABTS_INT_EQUAL(tc, origpath[0], root[0]);
325 {
326 char *pt = strchr(root, ':');
327 ABTS_PTR_NOTNULL(tc, pt);
328 ABTS_INT_EQUAL(tc, ':', pt[0]);
329 ABTS_INT_EQUAL(tc, '/', pt[1]);
330 ABTS_INT_EQUAL(tc, 0, pt[2]);
331 pt = strchr(origpath, ':');
332 ABTS_PTR_NOTNULL(tc, pt);
333 ABTS_STR_EQUAL(tc, (pt+2), path);
334 }
335 #else
336 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
337 ABTS_STR_EQUAL(tc, "/", root);
338 ABTS_STR_EQUAL(tc, origpath + 1, path);
339 #endif
340
341 rv = apr_filepath_merge(&testpath, root, path,
342 APR_FILEPATH_TRUENAME
343 | APR_FILEPATH_NOTABOVEROOT
344 | APR_FILEPATH_NOTRELATIVE, p);
345 ABTS_INT_EQUAL(tc, APR_SUCCESS, rv);
346 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
347 hadfailed = tc->failed;
348 #endif
349 /* The API doesn't promise equality!!!
350 * apr_filepath_get never promised a canonical filepath.
351 * We'll emit noise under verbose so the user is aware,
352 * but translate this back to success.
353 */
354 ABTS_STR_EQUAL(tc, origpath, testpath);
355 #if defined(WIN32) || defined(OS2) || defined(NETWARE)
356 if (!hadfailed) tc->failed = 0;
357 #endif
358 }
359
360
testnames(abts_suite * suite)361 abts_suite *testnames(abts_suite *suite)
362 {
363 suite = ADD_SUITE(suite)
364
365 abts_run_test(suite, merge_aboveroot, NULL);
366 abts_run_test(suite, merge_belowroot, NULL);
367 abts_run_test(suite, merge_noflag, NULL);
368 abts_run_test(suite, merge_dotdot, NULL);
369 abts_run_test(suite, merge_secure, NULL);
370 abts_run_test(suite, merge_notrel, NULL);
371 abts_run_test(suite, merge_notrelfail, NULL);
372 abts_run_test(suite, merge_notabs, NULL);
373 abts_run_test(suite, merge_notabsfail, NULL);
374 abts_run_test(suite, merge_dotdot_dotdot_dotdot, NULL);
375 #if defined(WIN32)
376 abts_run_test(suite, merge_lowercasedrive, NULL);
377 abts_run_test(suite, merge_shortname, NULL);
378 #endif
379
380 abts_run_test(suite, root_absolute, NULL);
381 abts_run_test(suite, root_relative, NULL);
382 abts_run_test(suite, root_from_slash, NULL);
383 abts_run_test(suite, root_from_cwd_and_back, NULL);
384
385 return suite;
386 }
387
388