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 38static 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 52static 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 64static 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 75static 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 99static 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 117static 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 128static 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 140static 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 155static 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 170static 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) 184static 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 219static 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 232static 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 247static 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 265static 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 328abts_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