]>
| Commit | Line | Data |
|---|---|---|
| 8f22fe32 YW |
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
| 2 | ||
| fa34123c | 3 | #include <stdlib.h> |
| 8f22fe32 YW |
4 | #include <unistd.h> |
| 5 | ||
| 6 | #include "alloc-util.h" | |
| fa34123c | 7 | #include "argv-util.h" |
| 8f22fe32 YW |
8 | #include "chase.h" |
| 9 | #include "dirent-util.h" | |
| 10 | #include "fd-util.h" | |
| 11 | #include "fs-util.h" | |
| 12 | #include "id128-util.h" | |
| 13 | #include "mkdir.h" | |
| 14 | #include "path-util.h" | |
| e49e76d6 | 15 | #include "random-util.h" |
| 8f22fe32 | 16 | #include "rm-rf.h" |
| fa34123c | 17 | #include "stat-util.h" |
| 8f22fe32 YW |
18 | #include "string-util.h" |
| 19 | #include "tests.h" | |
| 20 | #include "tmpfile-util.h" | |
| fda65211 | 21 | #include "user-util.h" |
| 8f22fe32 YW |
22 | |
| 23 | static const char *arg_test_dir = NULL; | |
| 24 | ||
| 3991f35f YW |
25 | static void test_chase_extract_filename_one(const char *path, const char *root, const char *expected) { |
| 26 | _cleanup_free_ char *ret1 = NULL, *ret2 = NULL, *fname = NULL; | |
| 27 | ||
| 28 | log_debug("/* %s(path=%s, root=%s) */", __func__, path, strnull(root)); | |
| 29 | ||
| 30 | assert_se(chase(path, root, CHASE_EXTRACT_FILENAME, &ret1, NULL) > 0); | |
| c79e88b3 | 31 | ASSERT_STREQ(ret1, expected); |
| 3991f35f YW |
32 | |
| 33 | assert_se(chase(path, root, 0, &ret2, NULL) > 0); | |
| f9d273e6 UA |
34 | ASSERT_OK(chase_extract_filename(ret2, root, &fname)); |
| 35 | ASSERT_STREQ(fname, expected); | |
| 3991f35f YW |
36 | } |
| 37 | ||
| 8f22fe32 YW |
38 | TEST(chase) { |
| 39 | _cleanup_free_ char *result = NULL, *pwd = NULL; | |
| 40 | _cleanup_close_ int pfd = -EBADF; | |
| 41 | char *temp; | |
| 42 | const char *top, *p, *pslash, *q, *qslash; | |
| 43 | struct stat st; | |
| 44 | int r; | |
| 45 | ||
| 46 | temp = strjoina(arg_test_dir ?: "/tmp", "/test-chase.XXXXXX"); | |
| 47 | assert_se(mkdtemp(temp)); | |
| 48 | ||
| 49 | top = strjoina(temp, "/top"); | |
| f9d273e6 | 50 | ASSERT_OK(mkdir(top, 0700)); |
| 8f22fe32 YW |
51 | |
| 52 | p = strjoina(top, "/dot"); | |
| 53 | if (symlink(".", p) < 0) { | |
| 54 | assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM)); | |
| 55 | log_tests_skipped_errno(errno, "symlink() not possible"); | |
| 56 | goto cleanup; | |
| 57 | }; | |
| 58 | ||
| 59 | p = strjoina(top, "/dotdot"); | |
| f9d273e6 | 60 | ASSERT_OK(symlink("..", p)); |
| 8f22fe32 YW |
61 | |
| 62 | p = strjoina(top, "/dotdota"); | |
| f9d273e6 | 63 | ASSERT_OK(symlink("../a", p)); |
| 8f22fe32 YW |
64 | |
| 65 | p = strjoina(temp, "/a"); | |
| f9d273e6 | 66 | ASSERT_OK(symlink("b", p)); |
| 8f22fe32 YW |
67 | |
| 68 | p = strjoina(temp, "/b"); | |
| f9d273e6 | 69 | ASSERT_OK(symlink("/usr", p)); |
| 8f22fe32 YW |
70 | |
| 71 | p = strjoina(temp, "/start"); | |
| f9d273e6 | 72 | ASSERT_OK(symlink("top/dot/dotdota", p)); |
| 8f22fe32 YW |
73 | |
| 74 | /* Paths that use symlinks underneath the "root" */ | |
| 75 | ||
| 76 | r = chase(p, NULL, 0, &result, NULL); | |
| 77 | assert_se(r > 0); | |
| 78 | assert_se(path_equal(result, "/usr")); | |
| 79 | result = mfree(result); | |
| 80 | ||
| 83c57d8c YW |
81 | r = chase(p, "/.//../../../", 0, &result, NULL); |
| 82 | assert_se(r > 0); | |
| 83 | assert_se(path_equal(result, "/usr")); | |
| 84 | result = mfree(result); | |
| 85 | ||
| 8f22fe32 YW |
86 | pslash = strjoina(p, "/"); |
| 87 | r = chase(pslash, NULL, 0, &result, NULL); | |
| 88 | assert_se(r > 0); | |
| 89 | assert_se(path_equal(result, "/usr/")); | |
| 90 | result = mfree(result); | |
| 91 | ||
| 92 | r = chase(p, temp, 0, &result, NULL); | |
| 93 | assert_se(r == -ENOENT); | |
| 94 | ||
| 95 | r = chase(pslash, temp, 0, &result, NULL); | |
| 96 | assert_se(r == -ENOENT); | |
| 97 | ||
| 98 | q = strjoina(temp, "/usr"); | |
| 99 | ||
| 100 | r = chase(p, temp, CHASE_NONEXISTENT, &result, NULL); | |
| 101 | assert_se(r == 0); | |
| 102 | assert_se(path_equal(result, q)); | |
| 103 | result = mfree(result); | |
| 104 | ||
| 105 | qslash = strjoina(q, "/"); | |
| 106 | ||
| 107 | r = chase(pslash, temp, CHASE_NONEXISTENT, &result, NULL); | |
| 108 | assert_se(r == 0); | |
| 109 | assert_se(path_equal(result, qslash)); | |
| 110 | result = mfree(result); | |
| 111 | ||
| f9d273e6 | 112 | ASSERT_OK(mkdir(q, 0700)); |
| 8f22fe32 YW |
113 | |
| 114 | r = chase(p, temp, 0, &result, NULL); | |
| 115 | assert_se(r > 0); | |
| 116 | assert_se(path_equal(result, q)); | |
| 117 | result = mfree(result); | |
| 118 | ||
| 119 | r = chase(pslash, temp, 0, &result, NULL); | |
| 120 | assert_se(r > 0); | |
| 121 | assert_se(path_equal(result, qslash)); | |
| 122 | result = mfree(result); | |
| 123 | ||
| 124 | p = strjoina(temp, "/slash"); | |
| 125 | assert_se(symlink("/", p) >= 0); | |
| 126 | ||
| 127 | r = chase(p, NULL, 0, &result, NULL); | |
| 128 | assert_se(r > 0); | |
| 129 | assert_se(path_equal(result, "/")); | |
| 130 | result = mfree(result); | |
| 131 | ||
| 132 | r = chase(p, temp, 0, &result, NULL); | |
| 133 | assert_se(r > 0); | |
| 134 | assert_se(path_equal(result, temp)); | |
| 135 | result = mfree(result); | |
| 136 | ||
| 3991f35f YW |
137 | /* Tests for CHASE_EXTRACT_FILENAME and chase_extract_filename() */ |
| 138 | ||
| 139 | p = strjoina(temp, "/start"); | |
| 140 | pslash = strjoina(p, "/"); | |
| 141 | test_chase_extract_filename_one(p, NULL, "usr"); | |
| 142 | test_chase_extract_filename_one(pslash, NULL, "usr"); | |
| 143 | test_chase_extract_filename_one(p, temp, "usr"); | |
| 144 | test_chase_extract_filename_one(pslash, temp, "usr"); | |
| 145 | ||
| 146 | p = strjoina(temp, "/slash"); | |
| 147 | test_chase_extract_filename_one(p, NULL, "."); | |
| 148 | test_chase_extract_filename_one(p, temp, "."); | |
| 149 | ||
| 8f22fe32 YW |
150 | /* Paths that would "escape" outside of the "root" */ |
| 151 | ||
| 152 | p = strjoina(temp, "/6dots"); | |
| f9d273e6 | 153 | ASSERT_OK(symlink("../../..", p)); |
| 8f22fe32 YW |
154 | |
| 155 | r = chase(p, temp, 0, &result, NULL); | |
| 156 | assert_se(r > 0 && path_equal(result, temp)); | |
| 157 | result = mfree(result); | |
| 158 | ||
| 159 | p = strjoina(temp, "/6dotsusr"); | |
| f9d273e6 | 160 | ASSERT_OK(symlink("../../../usr", p)); |
| 8f22fe32 YW |
161 | |
| 162 | r = chase(p, temp, 0, &result, NULL); | |
| 163 | assert_se(r > 0 && path_equal(result, q)); | |
| 164 | result = mfree(result); | |
| 165 | ||
| 166 | p = strjoina(temp, "/top/8dotsusr"); | |
| f9d273e6 | 167 | ASSERT_OK(symlink("../../../../usr", p)); |
| 8f22fe32 YW |
168 | |
| 169 | r = chase(p, temp, 0, &result, NULL); | |
| 170 | assert_se(r > 0 && path_equal(result, q)); | |
| 171 | result = mfree(result); | |
| 172 | ||
| 173 | /* Paths that contain repeated slashes */ | |
| 174 | ||
| 175 | p = strjoina(temp, "/slashslash"); | |
| f9d273e6 | 176 | ASSERT_OK(symlink("///usr///", p)); |
| 8f22fe32 YW |
177 | |
| 178 | r = chase(p, NULL, 0, &result, NULL); | |
| 179 | assert_se(r > 0); | |
| 180 | assert_se(path_equal(result, "/usr")); | |
| c79e88b3 | 181 | ASSERT_STREQ(result, "/usr"); /* we guarantee that we drop redundant slashes */ |
| 8f22fe32 YW |
182 | result = mfree(result); |
| 183 | ||
| 184 | r = chase(p, temp, 0, &result, NULL); | |
| 185 | assert_se(r > 0); | |
| 186 | assert_se(path_equal(result, q)); | |
| 187 | result = mfree(result); | |
| 188 | ||
| 189 | /* Paths underneath the "root" with different UIDs while using CHASE_SAFE */ | |
| 190 | ||
| ef31767e | 191 | if (geteuid() == 0 && !userns_has_single_user()) { |
| 8f22fe32 | 192 | p = strjoina(temp, "/user"); |
| f9d273e6 UA |
193 | ASSERT_OK(mkdir(p, 0755)); |
| 194 | ASSERT_OK(chown(p, UID_NOBODY, GID_NOBODY)); | |
| 8f22fe32 YW |
195 | |
| 196 | q = strjoina(temp, "/user/root"); | |
| f9d273e6 | 197 | ASSERT_OK(mkdir(q, 0755)); |
| 8f22fe32 YW |
198 | |
| 199 | p = strjoina(q, "/link"); | |
| f9d273e6 | 200 | ASSERT_OK(symlink("/", p)); |
| 8f22fe32 YW |
201 | |
| 202 | /* Fail when user-owned directories contain root-owned subdirectories. */ | |
| 203 | r = chase(p, temp, CHASE_SAFE, &result, NULL); | |
| 204 | assert_se(r == -ENOLINK); | |
| 205 | result = mfree(result); | |
| 206 | ||
| 207 | /* Allow this when the user-owned directories are all in the "root". */ | |
| 208 | r = chase(p, q, CHASE_SAFE, &result, NULL); | |
| 209 | assert_se(r > 0); | |
| 210 | result = mfree(result); | |
| 211 | } | |
| 212 | ||
| 213 | /* Paths using . */ | |
| 214 | ||
| 215 | r = chase("/etc/./.././", NULL, 0, &result, NULL); | |
| 216 | assert_se(r > 0); | |
| 217 | assert_se(path_equal(result, "/")); | |
| 218 | result = mfree(result); | |
| 219 | ||
| 220 | r = chase("/etc/./.././", "/etc", 0, &result, NULL); | |
| 221 | assert_se(r > 0 && path_equal(result, "/etc")); | |
| 222 | result = mfree(result); | |
| 223 | ||
| 224 | r = chase("/../.././//../../etc", NULL, 0, &result, NULL); | |
| 225 | assert_se(r > 0); | |
| f9d273e6 | 226 | ASSERT_STREQ(result, "/etc"); |
| 8f22fe32 YW |
227 | result = mfree(result); |
| 228 | ||
| 229 | r = chase("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result, NULL); | |
| 230 | assert_se(r == 0); | |
| f9d273e6 | 231 | ASSERT_STREQ(result, "/test-chase.fsldajfl"); |
| 8f22fe32 YW |
232 | result = mfree(result); |
| 233 | ||
| 234 | r = chase("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result, NULL); | |
| 235 | assert_se(r > 0); | |
| f9d273e6 | 236 | ASSERT_STREQ(result, "/etc"); |
| 8f22fe32 YW |
237 | result = mfree(result); |
| 238 | ||
| 239 | r = chase("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result, NULL); | |
| 240 | assert_se(r == 0); | |
| f9d273e6 | 241 | ASSERT_STREQ(result, "/test-chase.fsldajfl"); |
| 8f22fe32 YW |
242 | result = mfree(result); |
| 243 | ||
| 7efaab48 DDM |
244 | r = chase("/.path/with/dot", temp, CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result, NULL); |
| 245 | ASSERT_OK(r); | |
| 246 | q = strjoina(temp, "/.path/with/dot"); | |
| 247 | ASSERT_STREQ(result, q); | |
| 248 | result = mfree(result); | |
| 249 | ||
| 8f22fe32 YW |
250 | r = chase("/etc/machine-id/foo", NULL, 0, &result, NULL); |
| 251 | assert_se(IN_SET(r, -ENOTDIR, -ENOENT)); | |
| 252 | result = mfree(result); | |
| 253 | ||
| 254 | /* Path that loops back to self */ | |
| 255 | ||
| 256 | p = strjoina(temp, "/recursive-symlink"); | |
| f9d273e6 | 257 | ASSERT_OK(symlink("recursive-symlink", p)); |
| 8f22fe32 YW |
258 | r = chase(p, NULL, 0, &result, NULL); |
| 259 | assert_se(r == -ELOOP); | |
| 260 | ||
| 261 | /* Path which doesn't exist */ | |
| 262 | ||
| 263 | p = strjoina(temp, "/idontexist"); | |
| 264 | r = chase(p, NULL, 0, &result, NULL); | |
| 265 | assert_se(r == -ENOENT); | |
| 266 | ||
| 267 | r = chase(p, NULL, CHASE_NONEXISTENT, &result, NULL); | |
| 268 | assert_se(r == 0); | |
| 269 | assert_se(path_equal(result, p)); | |
| 270 | result = mfree(result); | |
| 271 | ||
| 272 | p = strjoina(temp, "/idontexist/meneither"); | |
| 273 | r = chase(p, NULL, 0, &result, NULL); | |
| 274 | assert_se(r == -ENOENT); | |
| 275 | ||
| 276 | r = chase(p, NULL, CHASE_NONEXISTENT, &result, NULL); | |
| 277 | assert_se(r == 0); | |
| 278 | assert_se(path_equal(result, p)); | |
| 279 | result = mfree(result); | |
| 280 | ||
| 281 | /* Relative paths */ | |
| 282 | ||
| f9d273e6 | 283 | ASSERT_OK(safe_getcwd(&pwd)); |
| 8f22fe32 | 284 | |
| f9d273e6 | 285 | ASSERT_OK(chdir(temp)); |
| 8f22fe32 YW |
286 | |
| 287 | p = "this/is/a/relative/path"; | |
| 288 | r = chase(p, NULL, CHASE_NONEXISTENT, &result, NULL); | |
| 289 | assert_se(r == 0); | |
| 290 | ||
| 291 | p = strjoina(temp, "/", p); | |
| 292 | assert_se(path_equal(result, p)); | |
| 293 | result = mfree(result); | |
| 294 | ||
| 295 | p = "this/is/a/relative/path"; | |
| 296 | r = chase(p, temp, CHASE_NONEXISTENT, &result, NULL); | |
| 297 | assert_se(r == 0); | |
| 298 | ||
| 299 | p = strjoina(temp, "/", p); | |
| 300 | assert_se(path_equal(result, p)); | |
| 301 | result = mfree(result); | |
| 302 | ||
| 303 | assert_se(chdir(pwd) >= 0); | |
| 304 | ||
| 305 | /* Path which doesn't exist, but contains weird stuff */ | |
| 306 | ||
| 307 | p = strjoina(temp, "/idontexist/.."); | |
| 308 | r = chase(p, NULL, 0, &result, NULL); | |
| 309 | assert_se(r == -ENOENT); | |
| 310 | ||
| 311 | r = chase(p, NULL, CHASE_NONEXISTENT, &result, NULL); | |
| 312 | assert_se(r == -ENOENT); | |
| 313 | ||
| 314 | p = strjoina(temp, "/target"); | |
| 315 | q = strjoina(temp, "/top"); | |
| 316 | assert_se(symlink(q, p) >= 0); | |
| 317 | p = strjoina(temp, "/target/idontexist"); | |
| 318 | r = chase(p, NULL, 0, &result, NULL); | |
| 319 | assert_se(r == -ENOENT); | |
| 320 | ||
| ef31767e | 321 | if (geteuid() == 0 && !userns_has_single_user()) { |
| 8f22fe32 | 322 | p = strjoina(temp, "/priv1"); |
| f9d273e6 | 323 | ASSERT_OK(mkdir(p, 0755)); |
| 8f22fe32 YW |
324 | |
| 325 | q = strjoina(p, "/priv2"); | |
| f9d273e6 | 326 | ASSERT_OK(mkdir(q, 0755)); |
| 8f22fe32 | 327 | |
| f9d273e6 | 328 | ASSERT_OK(chase(q, NULL, CHASE_SAFE, NULL, NULL)); |
| 8f22fe32 | 329 | |
| f9d273e6 UA |
330 | ASSERT_OK(chown(q, UID_NOBODY, GID_NOBODY)); |
| 331 | ASSERT_OK(chase(q, NULL, CHASE_SAFE, NULL, NULL)); | |
| 8f22fe32 | 332 | |
| f9d273e6 UA |
333 | ASSERT_OK(chown(p, UID_NOBODY, GID_NOBODY)); |
| 334 | ASSERT_OK(chase(q, NULL, CHASE_SAFE, NULL, NULL)); | |
| 8f22fe32 YW |
335 | |
| 336 | assert_se(chown(q, 0, 0) >= 0); | |
| 337 | assert_se(chase(q, NULL, CHASE_SAFE, NULL, NULL) == -ENOLINK); | |
| 338 | ||
| f9d273e6 UA |
339 | ASSERT_OK(rmdir(q)); |
| 340 | ASSERT_OK(symlink("/etc/passwd", q)); | |
| 8f22fe32 YW |
341 | assert_se(chase(q, NULL, CHASE_SAFE, NULL, NULL) == -ENOLINK); |
| 342 | ||
| 343 | assert_se(chown(p, 0, 0) >= 0); | |
| f9d273e6 | 344 | ASSERT_OK(chase(q, NULL, CHASE_SAFE, NULL, NULL)); |
| 8f22fe32 YW |
345 | } |
| 346 | ||
| 347 | p = strjoina(temp, "/machine-id-test"); | |
| f9d273e6 | 348 | ASSERT_OK(symlink("/usr/../etc/./machine-id", p)); |
| 8f22fe32 YW |
349 | |
| 350 | r = chase(p, NULL, 0, NULL, &pfd); | |
| 351 | if (r != -ENOENT && sd_id128_get_machine(NULL) >= 0) { | |
| 352 | _cleanup_close_ int fd = -EBADF; | |
| 353 | sd_id128_t a, b; | |
| 354 | ||
| f9d273e6 | 355 | ASSERT_OK(pfd); |
| 8f22fe32 YW |
356 | |
| 357 | fd = fd_reopen(pfd, O_RDONLY|O_CLOEXEC); | |
| f9d273e6 | 358 | ASSERT_OK(fd); |
| 8f22fe32 YW |
359 | safe_close(pfd); |
| 360 | ||
| f9d273e6 UA |
361 | ASSERT_OK(id128_read_fd(fd, ID128_FORMAT_PLAIN, &a)); |
| 362 | ASSERT_OK(sd_id128_get_machine(&b)); | |
| 8f22fe32 YW |
363 | assert_se(sd_id128_equal(a, b)); |
| 364 | } | |
| 365 | ||
| 366 | assert_se(lstat(p, &st) >= 0); | |
| 367 | r = chase_and_unlink(p, NULL, 0, 0, &result); | |
| 368 | assert_se(r == 0); | |
| 369 | assert_se(path_equal(result, p)); | |
| 370 | result = mfree(result); | |
| 371 | assert_se(lstat(p, &st) == -1 && errno == ENOENT); | |
| 372 | ||
| 373 | /* Test CHASE_NOFOLLOW */ | |
| 374 | ||
| 375 | p = strjoina(temp, "/target"); | |
| 376 | q = strjoina(temp, "/symlink"); | |
| 377 | assert_se(symlink(p, q) >= 0); | |
| 378 | r = chase(q, NULL, CHASE_NOFOLLOW, &result, &pfd); | |
| f9d273e6 UA |
379 | ASSERT_OK(r); |
| 380 | ASSERT_OK(pfd); | |
| 8f22fe32 | 381 | assert_se(path_equal(result, q)); |
| f9d273e6 | 382 | ASSERT_OK(fstat(pfd, &st)); |
| 8f22fe32 YW |
383 | assert_se(S_ISLNK(st.st_mode)); |
| 384 | result = mfree(result); | |
| 385 | pfd = safe_close(pfd); | |
| 386 | ||
| 387 | /* s1 -> s2 -> nonexistent */ | |
| 388 | q = strjoina(temp, "/s1"); | |
| f9d273e6 | 389 | ASSERT_OK(symlink("s2", q)); |
| 8f22fe32 | 390 | p = strjoina(temp, "/s2"); |
| f9d273e6 | 391 | ASSERT_OK(symlink("nonexistent", p)); |
| 8f22fe32 | 392 | r = chase(q, NULL, CHASE_NOFOLLOW, &result, &pfd); |
| f9d273e6 UA |
393 | ASSERT_OK(r); |
| 394 | ASSERT_OK(pfd); | |
| 8f22fe32 | 395 | assert_se(path_equal(result, q)); |
| f9d273e6 | 396 | ASSERT_OK(fstat(pfd, &st)); |
| 8f22fe32 YW |
397 | assert_se(S_ISLNK(st.st_mode)); |
| 398 | result = mfree(result); | |
| 399 | pfd = safe_close(pfd); | |
| 400 | ||
| 401 | /* Test CHASE_STEP */ | |
| 402 | ||
| 403 | p = strjoina(temp, "/start"); | |
| 404 | r = chase(p, NULL, CHASE_STEP, &result, NULL); | |
| 405 | assert_se(r == 0); | |
| 406 | p = strjoina(temp, "/top/dot/dotdota"); | |
| f9d273e6 | 407 | ASSERT_STREQ(p, result); |
| 8f22fe32 YW |
408 | result = mfree(result); |
| 409 | ||
| 410 | r = chase(p, NULL, CHASE_STEP, &result, NULL); | |
| 411 | assert_se(r == 0); | |
| 412 | p = strjoina(temp, "/top/dotdota"); | |
| f9d273e6 | 413 | ASSERT_STREQ(p, result); |
| 8f22fe32 YW |
414 | result = mfree(result); |
| 415 | ||
| 416 | r = chase(p, NULL, CHASE_STEP, &result, NULL); | |
| 417 | assert_se(r == 0); | |
| 418 | p = strjoina(temp, "/top/../a"); | |
| f9d273e6 | 419 | ASSERT_STREQ(p, result); |
| 8f22fe32 YW |
420 | result = mfree(result); |
| 421 | ||
| 422 | r = chase(p, NULL, CHASE_STEP, &result, NULL); | |
| 423 | assert_se(r == 0); | |
| 424 | p = strjoina(temp, "/a"); | |
| f9d273e6 | 425 | ASSERT_STREQ(p, result); |
| 8f22fe32 YW |
426 | result = mfree(result); |
| 427 | ||
| 428 | r = chase(p, NULL, CHASE_STEP, &result, NULL); | |
| 429 | assert_se(r == 0); | |
| 430 | p = strjoina(temp, "/b"); | |
| f9d273e6 | 431 | ASSERT_STREQ(p, result); |
| 8f22fe32 YW |
432 | result = mfree(result); |
| 433 | ||
| 434 | r = chase(p, NULL, CHASE_STEP, &result, NULL); | |
| 435 | assert_se(r == 0); | |
| f9d273e6 | 436 | ASSERT_STREQ("/usr", result); |
| 8f22fe32 YW |
437 | result = mfree(result); |
| 438 | ||
| 439 | r = chase("/usr", NULL, CHASE_STEP, &result, NULL); | |
| 440 | assert_se(r > 0); | |
| f9d273e6 | 441 | ASSERT_STREQ("/usr", result); |
| 8f22fe32 YW |
442 | result = mfree(result); |
| 443 | ||
| 444 | /* Make sure that symlinks in the "root" path are not resolved, but those below are */ | |
| 445 | p = strjoina("/etc/..", temp, "/self"); | |
| 446 | assert_se(symlink(".", p) >= 0); | |
| 447 | q = strjoina(p, "/top/dot/dotdota"); | |
| 448 | r = chase(q, p, 0, &result, NULL); | |
| 449 | assert_se(r > 0); | |
| 450 | assert_se(path_equal(path_startswith(result, p), "usr")); | |
| 451 | result = mfree(result); | |
| 452 | ||
| 453 | /* Test CHASE_PROHIBIT_SYMLINKS */ | |
| 454 | ||
| 455 | assert_se(chase("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG); | |
| 456 | assert_se(chase("top/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG); | |
| 457 | assert_se(chase("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG); | |
| 458 | assert_se(chase("top/dotdot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG); | |
| 459 | assert_se(chase("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS, NULL, NULL) == -EREMCHG); | |
| 460 | assert_se(chase("top/dot/dot", temp, CHASE_PREFIX_ROOT|CHASE_PROHIBIT_SYMLINKS|CHASE_WARN, NULL, NULL) == -EREMCHG); | |
| 461 | ||
| 462 | cleanup: | |
| f9d273e6 | 463 | ASSERT_OK(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL)); |
| 8f22fe32 YW |
464 | } |
| 465 | ||
| 466 | TEST(chaseat) { | |
| 467 | _cleanup_(rm_rf_physical_and_freep) char *t = NULL; | |
| 468 | _cleanup_close_ int tfd = -EBADF, fd = -EBADF; | |
| 469 | _cleanup_free_ char *result = NULL; | |
| 470 | _cleanup_closedir_ DIR *dir = NULL; | |
| 471 | _cleanup_fclose_ FILE *f = NULL; | |
| 472 | struct stat st; | |
| 473 | const char *p; | |
| 474 | ||
| d9000d70 | 475 | ASSERT_OK(tfd = mkdtemp_open(NULL, 0, &t)); |
| 8f22fe32 YW |
476 | |
| 477 | /* Test that AT_FDCWD with CHASE_AT_RESOLVE_IN_ROOT resolves against / and not the current working | |
| 478 | * directory. */ | |
| 479 | ||
| f9d273e6 | 480 | ASSERT_OK(symlinkat("/usr", tfd, "abc")); |
| 8f22fe32 YW |
481 | |
| 482 | p = strjoina(t, "/abc"); | |
| f9d273e6 UA |
483 | ASSERT_OK(chaseat(AT_FDCWD, p, CHASE_AT_RESOLVE_IN_ROOT, &result, NULL)); |
| 484 | ASSERT_STREQ(result, "/usr"); | |
| 8f22fe32 YW |
485 | result = mfree(result); |
| 486 | ||
| c0552b35 YW |
487 | /* If the file descriptor points to the root directory, the result will be absolute. */ |
| 488 | ||
| 489 | fd = open("/", O_CLOEXEC | O_DIRECTORY | O_PATH); | |
| f9d273e6 | 490 | ASSERT_OK(fd); |
| c0552b35 | 491 | |
| f9d273e6 UA |
492 | ASSERT_OK(chaseat(fd, p, 0, &result, NULL)); |
| 493 | ASSERT_STREQ(result, "/usr"); | |
| c0552b35 YW |
494 | result = mfree(result); |
| 495 | ||
| f9d273e6 UA |
496 | ASSERT_OK(chaseat(fd, p, CHASE_AT_RESOLVE_IN_ROOT, &result, NULL)); |
| 497 | ASSERT_STREQ(result, "/usr"); | |
| c0552b35 YW |
498 | result = mfree(result); |
| 499 | ||
| 500 | fd = safe_close(fd); | |
| 501 | ||
| 24be89eb YW |
502 | /* If the file descriptor does not point to the root directory, the result will be relative |
| 503 | * unless the result is outside of the specified file descriptor. */ | |
| 504 | ||
| f9d273e6 UA |
505 | ASSERT_OK(chaseat(tfd, "abc", 0, &result, NULL)); |
| 506 | ASSERT_STREQ(result, "/usr"); | |
| 24be89eb YW |
507 | result = mfree(result); |
| 508 | ||
| f9d273e6 UA |
509 | ASSERT_OK(chaseat(tfd, "/abc", 0, &result, NULL)); |
| 510 | ASSERT_STREQ(result, "/usr"); | |
| 24be89eb | 511 | result = mfree(result); |
| c0552b35 YW |
512 | |
| 513 | assert_se(chaseat(tfd, "abc", CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL) == -ENOENT); | |
| 514 | assert_se(chaseat(tfd, "/abc", CHASE_AT_RESOLVE_IN_ROOT, NULL, NULL) == -ENOENT); | |
| 515 | ||
| f9d273e6 UA |
516 | ASSERT_OK(chaseat(tfd, "abc", CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &result, NULL)); |
| 517 | ASSERT_STREQ(result, "usr"); | |
| c0552b35 YW |
518 | result = mfree(result); |
| 519 | ||
| f9d273e6 UA |
520 | ASSERT_OK(chaseat(tfd, "/abc", CHASE_AT_RESOLVE_IN_ROOT | CHASE_NONEXISTENT, &result, NULL)); |
| 521 | ASSERT_STREQ(result, "usr"); | |
| c0552b35 YW |
522 | result = mfree(result); |
| 523 | ||
| 8f22fe32 YW |
524 | /* Test that absolute path or not are the same when resolving relative to a directory file |
| 525 | * descriptor and that we always get a relative path back. */ | |
| 526 | ||
| d9000d70 | 527 | ASSERT_OK(fd = openat(tfd, "def", O_CREAT|O_CLOEXEC, 0700)); |
| 8f22fe32 | 528 | fd = safe_close(fd); |
| f9d273e6 UA |
529 | ASSERT_OK(symlinkat("/def", tfd, "qed")); |
| 530 | ASSERT_OK(chaseat(tfd, "qed", CHASE_AT_RESOLVE_IN_ROOT, &result, NULL)); | |
| 531 | ASSERT_STREQ(result, "def"); | |
| 8f22fe32 | 532 | result = mfree(result); |
| f9d273e6 UA |
533 | ASSERT_OK(chaseat(tfd, "/qed", CHASE_AT_RESOLVE_IN_ROOT, &result, NULL)); |
| 534 | ASSERT_STREQ(result, "def"); | |
| 8f22fe32 YW |
535 | result = mfree(result); |
| 536 | ||
| 537 | /* Valid directory file descriptor without CHASE_AT_RESOLVE_IN_ROOT should resolve symlinks against | |
| 538 | * host's root. */ | |
| 539 | assert_se(chaseat(tfd, "/qed", 0, NULL, NULL) == -ENOENT); | |
| 540 | ||
| 541 | /* Test CHASE_PARENT */ | |
| 542 | ||
| d9000d70 | 543 | ASSERT_OK(fd = open_mkdir_at(tfd, "chase", O_CLOEXEC, 0755)); |
| f9d273e6 | 544 | ASSERT_OK(symlinkat("/def", fd, "parent")); |
| 8f22fe32 YW |
545 | fd = safe_close(fd); |
| 546 | ||
| 547 | /* Make sure that when we chase a symlink parent directory, that we chase the parent directory of the | |
| 548 | * symlink target and not the symlink itself. But if we add CHASE_NOFOLLOW, we get the parent | |
| 549 | * directory of the symlink itself. */ | |
| 550 | ||
| f9d273e6 UA |
551 | ASSERT_OK(chaseat(tfd, "chase/parent", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, &fd)); |
| 552 | ASSERT_OK(faccessat(fd, "def", F_OK, 0)); | |
| 553 | ASSERT_STREQ(result, "def"); | |
| 8f22fe32 YW |
554 | fd = safe_close(fd); |
| 555 | result = mfree(result); | |
| 556 | ||
| f9d273e6 UA |
557 | ASSERT_OK(chaseat(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_NOFOLLOW, &result, &fd)); |
| 558 | ASSERT_OK(faccessat(fd, "parent", F_OK, AT_SYMLINK_NOFOLLOW)); | |
| 559 | ASSERT_STREQ(result, "chase/parent"); | |
| 8f22fe32 YW |
560 | fd = safe_close(fd); |
| 561 | result = mfree(result); | |
| 562 | ||
| f9d273e6 UA |
563 | ASSERT_OK(chaseat(tfd, "chase", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, &fd)); |
| 564 | ASSERT_OK(faccessat(fd, "chase", F_OK, 0)); | |
| 565 | ASSERT_STREQ(result, "chase"); | |
| 8f22fe32 YW |
566 | fd = safe_close(fd); |
| 567 | result = mfree(result); | |
| 568 | ||
| f9d273e6 UA |
569 | ASSERT_OK(chaseat(tfd, "/", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, NULL)); |
| 570 | ASSERT_STREQ(result, "."); | |
| 8f22fe32 YW |
571 | result = mfree(result); |
| 572 | ||
| f9d273e6 UA |
573 | assert_se(chaseat(tfd, ".", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT, &result, NULL)); |
| 574 | ASSERT_STREQ(result, "."); | |
| 8f22fe32 YW |
575 | result = mfree(result); |
| 576 | ||
| 577 | /* Test CHASE_MKDIR_0755 */ | |
| 578 | ||
| f9d273e6 UA |
579 | ASSERT_OK(chaseat(tfd, "m/k/d/i/r", CHASE_MKDIR_0755|CHASE_NONEXISTENT, &result, NULL)); |
| 580 | ASSERT_OK(faccessat(tfd, "m/k/d/i", F_OK, 0)); | |
| 8f22fe32 | 581 | assert_se(RET_NERRNO(faccessat(tfd, "m/k/d/i/r", F_OK, 0)) == -ENOENT); |
| f9d273e6 | 582 | ASSERT_STREQ(result, "m/k/d/i/r"); |
| 8f22fe32 YW |
583 | result = mfree(result); |
| 584 | ||
| f9d273e6 UA |
585 | ASSERT_OK(chaseat(tfd, "m/../q", CHASE_MKDIR_0755|CHASE_NONEXISTENT, &result, NULL)); |
| 586 | ASSERT_OK(faccessat(tfd, "m", F_OK, 0)); | |
| 8f22fe32 | 587 | assert_se(RET_NERRNO(faccessat(tfd, "q", F_OK, 0)) == -ENOENT); |
| f9d273e6 | 588 | ASSERT_STREQ(result, "q"); |
| 8f22fe32 YW |
589 | result = mfree(result); |
| 590 | ||
| 4ea0bcb9 | 591 | assert_se(chaseat(tfd, "i/../p", CHASE_MKDIR_0755|CHASE_NONEXISTENT, NULL, NULL) == -ENOENT); |
| 8f22fe32 | 592 | |
| f5dc1adc | 593 | /* Test CHASE_EXTRACT_FILENAME */ |
| 8f22fe32 | 594 | |
| f9d273e6 UA |
595 | ASSERT_OK(chaseat(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_PARENT|CHASE_NOFOLLOW|CHASE_EXTRACT_FILENAME, &result, &fd)); |
| 596 | ASSERT_OK(faccessat(fd, result, F_OK, AT_SYMLINK_NOFOLLOW)); | |
| 597 | ASSERT_STREQ(result, "parent"); | |
| 8f22fe32 YW |
598 | fd = safe_close(fd); |
| 599 | result = mfree(result); | |
| 600 | ||
| f9d273e6 UA |
601 | ASSERT_OK(chaseat(tfd, "chase", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_EXTRACT_FILENAME, &result, &fd)); |
| 602 | ASSERT_OK(faccessat(fd, result, F_OK, 0)); | |
| 603 | ASSERT_STREQ(result, "chase"); | |
| 8f22fe32 YW |
604 | fd = safe_close(fd); |
| 605 | result = mfree(result); | |
| 606 | ||
| f9d273e6 UA |
607 | ASSERT_OK(chaseat(tfd, "/", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_EXTRACT_FILENAME, &result, NULL)); |
| 608 | ASSERT_STREQ(result, "."); | |
| 8f22fe32 YW |
609 | result = mfree(result); |
| 610 | ||
| f9d273e6 UA |
611 | ASSERT_OK(chaseat(tfd, ".", CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_EXTRACT_FILENAME, &result, NULL)); |
| 612 | ASSERT_STREQ(result, "."); | |
| 8f22fe32 YW |
613 | result = mfree(result); |
| 614 | ||
| f9d273e6 UA |
615 | ASSERT_OK(chaseat(tfd, NULL, CHASE_PARENT|CHASE_AT_RESOLVE_IN_ROOT|CHASE_EXTRACT_FILENAME, &result, NULL)); |
| 616 | ASSERT_STREQ(result, "."); | |
| 3c8f449c DDM |
617 | result = mfree(result); |
| 618 | ||
| 8f22fe32 YW |
619 | /* Test chase_and_openat() */ |
| 620 | ||
| 621 | fd = chase_and_openat(tfd, "o/p/e/n/f/i/l/e", CHASE_MKDIR_0755, O_CREAT|O_EXCL|O_CLOEXEC, NULL); | |
| f9d273e6 UA |
622 | ASSERT_OK(fd); |
| 623 | ASSERT_OK(fd_verify_regular(fd)); | |
| 8f22fe32 YW |
624 | fd = safe_close(fd); |
| 625 | ||
| 626 | fd = chase_and_openat(tfd, "o/p/e/n/d/i/r", CHASE_MKDIR_0755, O_DIRECTORY|O_CREAT|O_EXCL|O_CLOEXEC, NULL); | |
| f9d273e6 UA |
627 | ASSERT_OK(fd); |
| 628 | ASSERT_OK(fd_verify_directory(fd)); | |
| 8f22fe32 YW |
629 | fd = safe_close(fd); |
| 630 | ||
| 8b85333c | 631 | fd = chase_and_openat(tfd, NULL, CHASE_PARENT|CHASE_EXTRACT_FILENAME, O_PATH|O_DIRECTORY|O_CLOEXEC, &result); |
| f9d273e6 UA |
632 | ASSERT_OK(fd); |
| 633 | ASSERT_STREQ(result, "."); | |
| 8b85333c DDM |
634 | fd = safe_close(fd); |
| 635 | result = mfree(result); | |
| 636 | ||
| 8f22fe32 YW |
637 | /* Test chase_and_openatdir() */ |
| 638 | ||
| f9d273e6 | 639 | ASSERT_OK(chase_and_opendirat(tfd, "o/p/e/n/d/i", 0, &result, &dir)); |
| 8f22fe32 | 640 | FOREACH_DIRENT(de, dir, assert_not_reached()) |
| f9d273e6 UA |
641 | ASSERT_STREQ(de->d_name, "r"); |
| 642 | ASSERT_STREQ(result, "o/p/e/n/d/i"); | |
| 8f22fe32 YW |
643 | result = mfree(result); |
| 644 | ||
| 645 | /* Test chase_and_statat() */ | |
| 646 | ||
| f9d273e6 UA |
647 | ASSERT_OK(chase_and_statat(tfd, "o/p", 0, &result, &st)); |
| 648 | ASSERT_OK(stat_verify_directory(&st)); | |
| 649 | ASSERT_STREQ(result, "o/p"); | |
| 8f22fe32 YW |
650 | result = mfree(result); |
| 651 | ||
| 652 | /* Test chase_and_accessat() */ | |
| 653 | ||
| f9d273e6 UA |
654 | ASSERT_OK(chase_and_accessat(tfd, "o/p/e", 0, F_OK, &result)); |
| 655 | ASSERT_STREQ(result, "o/p/e"); | |
| 8f22fe32 YW |
656 | result = mfree(result); |
| 657 | ||
| 658 | /* Test chase_and_fopenat_unlocked() */ | |
| 659 | ||
| f9d273e6 | 660 | ASSERT_OK(chase_and_fopenat_unlocked(tfd, "o/p/e/n/f/i/l/e", 0, "re", &result, &f)); |
| 8f22fe32 YW |
661 | assert_se(fread(&(char[1]) {}, 1, 1, f) == 0); |
| 662 | assert_se(feof(f)); | |
| 663 | f = safe_fclose(f); | |
| f9d273e6 | 664 | ASSERT_STREQ(result, "o/p/e/n/f/i/l/e"); |
| 8f22fe32 YW |
665 | result = mfree(result); |
| 666 | ||
| 667 | /* Test chase_and_unlinkat() */ | |
| 668 | ||
| f9d273e6 UA |
669 | ASSERT_OK(chase_and_unlinkat(tfd, "o/p/e/n/f/i/l/e", 0, 0, &result)); |
| 670 | ASSERT_STREQ(result, "o/p/e/n/f/i/l/e"); | |
| 8f22fe32 YW |
671 | result = mfree(result); |
| 672 | ||
| 673 | /* Test chase_and_open_parent_at() */ | |
| 674 | ||
| d9000d70 | 675 | ASSERT_OK(fd = chase_and_open_parent_at(tfd, "chase/parent", CHASE_AT_RESOLVE_IN_ROOT|CHASE_NOFOLLOW, &result)); |
| f9d273e6 UA |
676 | ASSERT_OK(faccessat(fd, result, F_OK, AT_SYMLINK_NOFOLLOW)); |
| 677 | ASSERT_STREQ(result, "parent"); | |
| 8f22fe32 YW |
678 | fd = safe_close(fd); |
| 679 | result = mfree(result); | |
| 680 | ||
| d9000d70 | 681 | ASSERT_OK(fd = chase_and_open_parent_at(tfd, "chase", CHASE_AT_RESOLVE_IN_ROOT, &result)); |
| f9d273e6 UA |
682 | ASSERT_OK(faccessat(fd, result, F_OK, 0)); |
| 683 | ASSERT_STREQ(result, "chase"); | |
| 8f22fe32 YW |
684 | fd = safe_close(fd); |
| 685 | result = mfree(result); | |
| 686 | ||
| d9000d70 | 687 | ASSERT_OK(fd = chase_and_open_parent_at(tfd, "/", CHASE_AT_RESOLVE_IN_ROOT, &result)); |
| f9d273e6 | 688 | ASSERT_STREQ(result, "."); |
| 8f22fe32 YW |
689 | fd = safe_close(fd); |
| 690 | result = mfree(result); | |
| 691 | ||
| d9000d70 | 692 | ASSERT_OK(fd = chase_and_open_parent_at(tfd, ".", CHASE_AT_RESOLVE_IN_ROOT, &result)); |
| f9d273e6 | 693 | ASSERT_STREQ(result, "."); |
| 8f22fe32 YW |
694 | fd = safe_close(fd); |
| 695 | result = mfree(result); | |
| 696 | } | |
| 697 | ||
| 60e761d8 YW |
698 | TEST(chaseat_prefix_root) { |
| 699 | _cleanup_free_ char *cwd = NULL, *ret = NULL, *expected = NULL; | |
| 700 | ||
| f9d273e6 | 701 | ASSERT_OK(safe_getcwd(&cwd)); |
| 60e761d8 | 702 | |
| f9d273e6 UA |
703 | ASSERT_OK(chaseat_prefix_root("/hoge", NULL, &ret)); |
| 704 | ASSERT_STREQ(ret, "/hoge"); | |
| 60e761d8 YW |
705 | |
| 706 | ret = mfree(ret); | |
| 707 | ||
| f9d273e6 UA |
708 | ASSERT_OK(chaseat_prefix_root("/hoge", "a/b/c", &ret)); |
| 709 | ASSERT_STREQ(ret, "/hoge"); | |
| 60e761d8 YW |
710 | |
| 711 | ret = mfree(ret); | |
| 712 | ||
| f9d273e6 UA |
713 | ASSERT_OK(chaseat_prefix_root("hoge", "/a/b//./c///", &ret)); |
| 714 | ASSERT_STREQ(ret, "/a/b/c/hoge"); | |
| 60e761d8 YW |
715 | |
| 716 | ret = mfree(ret); | |
| 717 | ||
| f9d273e6 | 718 | ASSERT_OK(chaseat_prefix_root("hoge", "a/b//./c///", &ret)); |
| 60e761d8 | 719 | assert_se(expected = path_join(cwd, "a/b/c/hoge")); |
| f9d273e6 | 720 | ASSERT_STREQ(ret, expected); |
| 60e761d8 YW |
721 | |
| 722 | ret = mfree(ret); | |
| 723 | expected = mfree(expected); | |
| 724 | ||
| f9d273e6 UA |
725 | ASSERT_OK(chaseat_prefix_root("./hoge/aaa/../././b", "/a/b//./c///", &ret)); |
| 726 | ASSERT_STREQ(ret, "/a/b/c/hoge/aaa/../././b"); | |
| 60e761d8 YW |
727 | |
| 728 | ret = mfree(ret); | |
| 729 | ||
| 730 | assert_se(chaseat_prefix_root("./hoge/aaa/../././b", "a/b//./c///", &ret) >= 0); | |
| 731 | assert_se(expected = path_join(cwd, "a/b/c/hoge/aaa/../././b")); | |
| c79e88b3 | 732 | ASSERT_STREQ(ret, expected); |
| 60e761d8 YW |
733 | } |
| 734 | ||
| 9c21cfdd LP |
735 | TEST(trailing_dot_dot) { |
| 736 | _cleanup_free_ char *path = NULL, *fdpath = NULL; | |
| 737 | _cleanup_close_ int fd = -EBADF; | |
| 738 | ||
| f9d273e6 | 739 | ASSERT_OK(chase("/usr/..", NULL, CHASE_PARENT, &path, &fd)); |
| 9c21cfdd | 740 | assert_se(path_equal(path, "/")); |
| f9d273e6 | 741 | ASSERT_OK(fd_get_path(fd, &fdpath)); |
| 9c21cfdd LP |
742 | assert_se(path_equal(fdpath, "/")); |
| 743 | ||
| 744 | path = mfree(path); | |
| 745 | fdpath = mfree(fdpath); | |
| 746 | fd = safe_close(fd); | |
| 747 | ||
| 748 | _cleanup_(rm_rf_physical_and_freep) char *t = NULL; | |
| f9d273e6 | 749 | ASSERT_OK(mkdtemp_malloc(NULL, &t)); |
| 9c21cfdd | 750 | _cleanup_free_ char *sub = ASSERT_PTR(path_join(t, "a/b/c/d")); |
| f9d273e6 | 751 | ASSERT_OK(mkdir_p(sub, 0700)); |
| 9c21cfdd | 752 | _cleanup_free_ char *suffixed = ASSERT_PTR(path_join(sub, "..")); |
| f9d273e6 | 753 | ASSERT_OK(chase(suffixed, NULL, CHASE_PARENT, &path, &fd)); |
| 9c21cfdd LP |
754 | _cleanup_free_ char *expected1 = ASSERT_PTR(path_join(t, "a/b/c")); |
| 755 | _cleanup_free_ char *expected2 = ASSERT_PTR(path_join(t, "a/b")); | |
| 756 | ||
| 757 | assert_se(path_equal(path, expected1)); | |
| f9d273e6 | 758 | ASSERT_OK(fd_get_path(fd, &fdpath)); |
| 9c21cfdd LP |
759 | assert_se(path_equal(fdpath, expected2)); |
| 760 | } | |
| 761 | ||
| e49e76d6 LP |
762 | TEST(use_chase_as_mkdir_p) { |
| 763 | _cleanup_free_ char *p = NULL; | |
| 764 | ASSERT_OK_ERRNO(asprintf(&p, "/tmp/chasemkdir%" PRIu64 "/a/b/c", random_u64())); | |
| 765 | ||
| 766 | _cleanup_close_ int fd = -EBADF; | |
| 767 | ASSERT_OK(chase(p, NULL, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755, NULL, &fd)); | |
| 768 | ||
| 769 | ASSERT_OK_EQ(inode_same_at(AT_FDCWD, p, fd, NULL, AT_EMPTY_PATH), 1); | |
| 770 | ||
| 771 | _cleanup_close_ int fd2 = -EBADF; | |
| 772 | ASSERT_OK(chase(p, p, CHASE_PREFIX_ROOT|CHASE_MKDIR_0755, NULL, &fd2)); | |
| 773 | ||
| 774 | _cleanup_free_ char *pp = ASSERT_PTR(path_join(p, p)); | |
| 775 | ||
| 776 | ASSERT_OK_EQ(inode_same_at(AT_FDCWD, pp, fd2, NULL, AT_EMPTY_PATH), 1); | |
| 777 | ||
| 778 | _cleanup_free_ char *f = NULL; | |
| 779 | ASSERT_OK(path_extract_directory(p, &f)); | |
| 780 | ||
| 781 | _cleanup_free_ char *ff = NULL; | |
| 782 | ASSERT_OK(path_extract_directory(f, &ff)); | |
| 783 | ||
| 784 | _cleanup_free_ char *fff = NULL; | |
| 785 | ASSERT_OK(path_extract_directory(ff, &fff)); | |
| 786 | ||
| 787 | ASSERT_OK(rm_rf(fff, REMOVE_PHYSICAL)); | |
| 788 | } | |
| 789 | ||
| c0dff420 YW |
790 | static int intro(void) { |
| 791 | arg_test_dir = saved_argv[1]; | |
| 792 | return EXIT_SUCCESS; | |
| 793 | } | |
| 794 | ||
| 8f22fe32 | 795 | DEFINE_TEST_MAIN_WITH_INTRO(LOG_INFO, intro); |