]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/test/test-path-util.c
test-path-util: add simple test for is_path() and is_device_path()
[thirdparty/systemd.git] / src / test / test-path-util.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <stdio.h>
4 #include <unistd.h>
5
6 #include "alloc-util.h"
7 #include "exec-util.h"
8 #include "fd-util.h"
9 #include "fs-util.h"
10 #include "macro.h"
11 #include "path-util.h"
12 #include "process-util.h"
13 #include "rm-rf.h"
14 #include "stat-util.h"
15 #include "string-util.h"
16 #include "strv.h"
17 #include "tests.h"
18 #include "tmpfile-util.h"
19
20 TEST(print_paths) {
21 log_info("DEFAULT_PATH=%s", DEFAULT_PATH);
22 log_info("DEFAULT_USER_PATH=%s", DEFAULT_USER_PATH);
23 }
24
25 TEST(path) {
26 assert_se(path_is_absolute("/"));
27 assert_se(!path_is_absolute("./"));
28
29 assert_se(streq(basename("./aa/bb/../file.da."), "file.da."));
30 assert_se(streq(basename("/aa///.file"), ".file"));
31 assert_se(streq(basename("/aa///file..."), "file..."));
32 assert_se(streq(basename("file.../"), ""));
33
34 assert_se(PATH_IN_SET("/bin", "/", "/bin", "/foo"));
35 assert_se(PATH_IN_SET("/bin", "/bin"));
36 assert_se(PATH_IN_SET("/bin", "/foo/bar", "/bin"));
37 assert_se(PATH_IN_SET("/", "/", "/", "/foo/bar"));
38 assert_se(!PATH_IN_SET("/", "/abc", "/def"));
39
40 assert_se(path_equal_ptr(NULL, NULL));
41 assert_se(path_equal_ptr("/a", "/a"));
42 assert_se(!path_equal_ptr("/a", "/b"));
43 assert_se(!path_equal_ptr("/a", NULL));
44 assert_se(!path_equal_ptr(NULL, "/a"));
45 }
46
47 TEST(is_path) {
48 assert_se(!is_path("foo"));
49 assert_se(!is_path("dos.ext"));
50 assert_se( is_path("/dir"));
51 assert_se( is_path("a/b"));
52 assert_se( is_path("a/b.ext"));
53
54 assert_se(!is_path("."));
55 assert_se(!is_path(""));
56 assert_se(!is_path(".."));
57
58 assert_se( is_path("/dev"));
59 assert_se( is_path("/./dev"));
60 assert_se( is_path("/./dev/."));
61 assert_se( is_path("/./dev."));
62 assert_se( is_path("//dev"));
63 assert_se( is_path("///dev"));
64 assert_se( is_path("/dev/"));
65 assert_se( is_path("///dev/"));
66 assert_se( is_path("/./dev/"));
67 assert_se( is_path("/../dev/"));
68 assert_se( is_path("/dev/sda"));
69 assert_se( is_path("/dev/sda5"));
70 assert_se( is_path("/dev/sda5b3"));
71 assert_se( is_path("/dev/sda5b3/idontexit"));
72 assert_se( is_path("/../dev/sda"));
73 assert_se( is_path("/../../dev/sda5"));
74 assert_se( is_path("/../../../dev/sda5b3"));
75 assert_se( is_path("/.././.././dev/sda5b3/idontexit"));
76 assert_se( is_path("/sys"));
77 assert_se( is_path("/sys/"));
78 assert_se( is_path("/./sys"));
79 assert_se( is_path("/./sys/."));
80 assert_se( is_path("/./sys."));
81 assert_se( is_path("/sys/what"));
82 assert_se( is_path("/sys/something/.."));
83 assert_se( is_path("/sys/something/../"));
84 assert_se( is_path("/sys////"));
85 assert_se( is_path("/sys////."));
86 assert_se( is_path("/sys/.."));
87 assert_se( is_path("/sys/../"));
88 assert_se( is_path("/usr/../dev/sda"));
89 }
90
91 TEST(is_device_path) {
92 assert_se(!is_device_path("foo"));
93 assert_se(!is_device_path("dos.ext"));
94 assert_se(!is_device_path("/dir"));
95 assert_se(!is_device_path("a/b"));
96 assert_se(!is_device_path("a/b.ext"));
97
98 assert_se(!is_device_path("."));
99 assert_se(!is_device_path(""));
100 assert_se(!is_device_path(".."));
101
102 assert_se( is_device_path("/dev"));
103 assert_se( is_device_path("/./dev"));
104 assert_se( is_device_path("/./dev/."));
105 assert_se(!is_device_path("/./dev."));
106 assert_se( is_device_path("/./dev/foo"));
107 assert_se( is_device_path("/./dev/./foo"));
108 assert_se(!is_device_path("/./dev./foo"));
109 assert_se( is_device_path("//dev"));
110 assert_se( is_device_path("///dev"));
111 assert_se( is_device_path("/dev/"));
112 assert_se( is_device_path("///dev/"));
113 assert_se( is_device_path("/./dev/"));
114 assert_se(!is_device_path("/../dev/"));
115 assert_se( is_device_path("/dev/sda"));
116 assert_se( is_device_path("/dev/sda5"));
117 assert_se( is_device_path("/dev/sda5b3"));
118 assert_se( is_device_path("/dev/sda5b3/idontexit"));
119 assert_se(!is_device_path("/../dev/sda"));
120 assert_se(!is_device_path("/../../dev/sda5"));
121 assert_se(!is_device_path("/../../../dev/sda5b3"));
122 assert_se(!is_device_path("/.././.././dev/sda5b3/idontexit"));
123 assert_se( is_device_path("/sys"));
124 assert_se( is_device_path("/sys/"));
125 assert_se( is_device_path("/./sys"));
126 assert_se( is_device_path("/./sys/."));
127 assert_se(!is_device_path("/./sys."));
128 assert_se( is_device_path("/./sys/foo"));
129 assert_se( is_device_path("/./sys/./foo"));
130 assert_se(!is_device_path("/./sys./foo"));
131 assert_se( is_device_path("/sys/what"));
132 assert_se( is_device_path("/sys/something/.."));
133 assert_se( is_device_path("/sys/something/../"));
134 assert_se( is_device_path("/sys////"));
135 assert_se( is_device_path("/sys////."));
136 assert_se( is_device_path("/sys/.."));
137 assert_se( is_device_path("/sys/../"));
138 assert_se(!is_device_path("/usr/../dev/sda"));
139 }
140
141 static void test_path_simplify_one(const char *in, const char *out, PathSimplifyFlags flags) {
142 char *p;
143
144 p = strdupa_safe(in);
145 path_simplify_full(p, flags);
146 log_debug("/* test_path_simplify(%s) → %s (expected: %s) */", in, p, out);
147 assert_se(streq(p, out));
148 }
149
150 TEST(path_simplify) {
151 _cleanup_free_ char *hoge = NULL, *hoge_out = NULL;
152 char foo[NAME_MAX * 2];
153
154 test_path_simplify_one("", "", 0);
155 test_path_simplify_one("aaa/bbb////ccc", "aaa/bbb/ccc", 0);
156 test_path_simplify_one("//aaa/.////ccc", "/aaa/ccc", 0);
157 test_path_simplify_one("///", "/", 0);
158 test_path_simplify_one("///", "/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
159 test_path_simplify_one("///.//", "/", 0);
160 test_path_simplify_one("///.//.///", "/", 0);
161 test_path_simplify_one("////.././///../.", "/../..", 0);
162 test_path_simplify_one(".", ".", 0);
163 test_path_simplify_one("./", ".", 0);
164 test_path_simplify_one("./", "./", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
165 test_path_simplify_one(".///.//./.", ".", 0);
166 test_path_simplify_one(".///.//././/", ".", 0);
167 test_path_simplify_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.",
168 "/aaa/.bbb/../c./d.dd/..eeee", 0);
169 test_path_simplify_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
170 "/aaa/.bbb/../c./d.dd/..eeee/..", 0);
171 test_path_simplify_one(".//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
172 "aaa/.bbb/../c./d.dd/..eeee/..", 0);
173 test_path_simplify_one("..//./aaa///.//./.bbb/..///c.//d.dd///..eeee/..",
174 "../aaa/.bbb/../c./d.dd/..eeee/..", 0);
175 test_path_simplify_one("abc///", "abc/", PATH_SIMPLIFY_KEEP_TRAILING_SLASH);
176
177 memset(foo, 'a', sizeof(foo) -1);
178 char_array_0(foo);
179
180 test_path_simplify_one(foo, foo, 0);
181
182 hoge = strjoin("/", foo);
183 assert_se(hoge);
184 test_path_simplify_one(hoge, hoge, 0);
185 hoge = mfree(hoge);
186
187 hoge = strjoin("a////.//././//./b///././/./c/////././//./", foo, "//.//////d/e/.//f/");
188 assert_se(hoge);
189
190 hoge_out = strjoin("a/b/c/", foo, "//.//////d/e/.//f/");
191 assert_se(hoge_out);
192
193 test_path_simplify_one(hoge, hoge_out, 0);
194 }
195
196 static void test_path_compare_one(const char *a, const char *b, int expected) {
197 int r;
198
199 assert_se(path_compare(a, a) == 0);
200 assert_se(path_compare(b, b) == 0);
201
202 r = path_compare(a, b);
203 assert_se((r > 0) == (expected > 0) && (r < 0) == (expected < 0));
204 r = path_compare(b, a);
205 assert_se((r < 0) == (expected > 0) && (r > 0) == (expected < 0));
206
207 assert_se(path_equal(a, a) == 1);
208 assert_se(path_equal(b, b) == 1);
209 assert_se(path_equal(a, b) == (expected == 0));
210 assert_se(path_equal(b, a) == (expected == 0));
211 }
212
213 TEST(path_compare) {
214 test_path_compare_one("/goo", "/goo", 0);
215 test_path_compare_one("/goo", "/goo", 0);
216 test_path_compare_one("//goo", "/goo", 0);
217 test_path_compare_one("//goo/////", "/goo", 0);
218 test_path_compare_one("goo/////", "goo", 0);
219 test_path_compare_one("/goo/boo", "/goo//boo", 0);
220 test_path_compare_one("//goo/boo", "/goo/boo//", 0);
221 test_path_compare_one("//goo/././//./boo//././//", "/goo/boo//.", 0);
222 test_path_compare_one("/.", "//.///", 0);
223 test_path_compare_one("/x", "x/", 1);
224 test_path_compare_one("x/", "/", -1);
225 test_path_compare_one("/x/./y", "x/y", 1);
226 test_path_compare_one("/x/./y", "/x/y", 0);
227 test_path_compare_one("/x/./././y", "/x/y/././.", 0);
228 test_path_compare_one("./x/./././y", "./x/y/././.", 0);
229 test_path_compare_one(".", "./.", 0);
230 test_path_compare_one(".", "././.", 0);
231 test_path_compare_one("./..", ".", 1);
232 test_path_compare_one("x/.y", "x/y", -1);
233 test_path_compare_one("foo", "/foo", -1);
234 test_path_compare_one("/foo", "/foo/bar", -1);
235 test_path_compare_one("/foo/aaa", "/foo/b", -1);
236 test_path_compare_one("/foo/aaa", "/foo/b/a", -1);
237 test_path_compare_one("/foo/a", "/foo/aaa", -1);
238 test_path_compare_one("/foo/a/b", "/foo/aaa", -1);
239 }
240
241 static void test_path_compare_filename_one(const char *a, const char *b, int expected) {
242 int r;
243
244 assert_se(path_compare_filename(a, a) == 0);
245 assert_se(path_compare_filename(b, b) == 0);
246
247 r = path_compare_filename(a, b);
248 assert_se((r > 0) == (expected > 0) && (r < 0) == (expected < 0));
249 r = path_compare_filename(b, a);
250 assert_se((r < 0) == (expected > 0) && (r > 0) == (expected < 0));
251
252 assert_se(path_equal_filename(a, a) == 1);
253 assert_se(path_equal_filename(b, b) == 1);
254 assert_se(path_equal_filename(a, b) == (expected == 0));
255 assert_se(path_equal_filename(b, a) == (expected == 0));
256 }
257
258 TEST(path_compare_filename) {
259 test_path_compare_filename_one("/goo", "/goo", 0);
260 test_path_compare_filename_one("/goo", "/goo", 0);
261 test_path_compare_filename_one("//goo", "/goo", 0);
262 test_path_compare_filename_one("//goo/////", "/goo", 0);
263 test_path_compare_filename_one("goo/////", "goo", 0);
264 test_path_compare_filename_one("/goo/boo", "/goo//boo", 0);
265 test_path_compare_filename_one("//goo/boo", "/goo/boo//", 0);
266 test_path_compare_filename_one("//goo/././//./boo//././//", "/goo/boo//.", 0);
267 test_path_compare_filename_one("/.", "//.///", -1);
268 test_path_compare_filename_one("/x", "x/", 0);
269 test_path_compare_filename_one("x/", "/", 1);
270 test_path_compare_filename_one("/x/./y", "x/y", 0);
271 test_path_compare_filename_one("/x/./y", "/x/y", 0);
272 test_path_compare_filename_one("/x/./././y", "/x/y/././.", 0);
273 test_path_compare_filename_one("./x/./././y", "./x/y/././.", 0);
274 test_path_compare_filename_one(".", "./.", -1);
275 test_path_compare_filename_one(".", "././.", -1);
276 test_path_compare_filename_one("./..", ".", 1);
277 test_path_compare_filename_one("x/.y", "x/y", -1);
278 test_path_compare_filename_one("foo", "/foo", 0);
279 test_path_compare_filename_one("/foo", "/foo/bar", 1);
280 test_path_compare_filename_one("/foo/aaa", "/foo/b", -1);
281 test_path_compare_filename_one("/foo/aaa", "/foo/b/a", 1);
282 test_path_compare_filename_one("/foo/a", "/foo/aaa", -1);
283 test_path_compare_filename_one("/foo/a/b", "/foo/aaa", 1);
284 test_path_compare_filename_one("/a/c", "/b/c", 0);
285 test_path_compare_filename_one("/a", "/a", 0);
286 test_path_compare_filename_one("/a/b", "/a/c", -1);
287 test_path_compare_filename_one("/b", "/c", -1);
288 }
289
290 TEST(path_equal_root) {
291 /* Nail down the details of how path_equal("/", ...) works. */
292
293 assert_se(path_equal("/", "/"));
294 assert_se(path_equal("/", "//"));
295
296 assert_se(path_equal("/", "/./"));
297 assert_se(!path_equal("/", "/../"));
298
299 assert_se(!path_equal("/", "/.../"));
300
301 /* Make sure that files_same works as expected. */
302
303 assert_se(inode_same("/", "/", 0) > 0);
304 assert_se(inode_same("/", "/", AT_SYMLINK_NOFOLLOW) > 0);
305 assert_se(inode_same("/", "//", 0) > 0);
306 assert_se(inode_same("/", "//", AT_SYMLINK_NOFOLLOW) > 0);
307
308 assert_se(inode_same("/", "/./", 0) > 0);
309 assert_se(inode_same("/", "/./", AT_SYMLINK_NOFOLLOW) > 0);
310 assert_se(inode_same("/", "/../", 0) > 0);
311 assert_se(inode_same("/", "/../", AT_SYMLINK_NOFOLLOW) > 0);
312
313 assert_se(inode_same("/", "/.../", 0) == -ENOENT);
314 assert_se(inode_same("/", "/.../", AT_SYMLINK_NOFOLLOW) == -ENOENT);
315
316 /* The same for path_equal_or_files_same. */
317
318 assert_se(path_equal_or_inode_same("/", "/", 0));
319 assert_se(path_equal_or_inode_same("/", "/", AT_SYMLINK_NOFOLLOW));
320 assert_se(path_equal_or_inode_same("/", "//", 0));
321 assert_se(path_equal_or_inode_same("/", "//", AT_SYMLINK_NOFOLLOW));
322
323 assert_se(path_equal_or_inode_same("/", "/./", 0));
324 assert_se(path_equal_or_inode_same("/", "/./", AT_SYMLINK_NOFOLLOW));
325 assert_se(path_equal_or_inode_same("/", "/../", 0));
326 assert_se(path_equal_or_inode_same("/", "/../", AT_SYMLINK_NOFOLLOW));
327
328 assert_se(!path_equal_or_inode_same("/", "/.../", 0));
329 assert_se(!path_equal_or_inode_same("/", "/.../", AT_SYMLINK_NOFOLLOW));
330 }
331
332 TEST(find_executable_full) {
333 char *p;
334 char* test_file_name;
335 _cleanup_close_ int fd = -EBADF;
336 char fn[] = "/tmp/test-XXXXXX";
337
338 assert_se(find_executable_full("sh", NULL, NULL, true, &p, NULL) == 0);
339 puts(p);
340 assert_se(streq(basename(p), "sh"));
341 free(p);
342
343 assert_se(find_executable_full("sh", NULL, NULL, false, &p, NULL) == 0);
344 puts(p);
345 assert_se(streq(basename(p), "sh"));
346 free(p);
347
348 _cleanup_free_ char *oldpath = NULL;
349 p = getenv("PATH");
350 if (p)
351 assert_se(oldpath = strdup(p));
352
353 assert_se(unsetenv("PATH") == 0);
354
355 assert_se(find_executable_full("sh", NULL, NULL, true, &p, NULL) == 0);
356 puts(p);
357 assert_se(streq(basename(p), "sh"));
358 free(p);
359
360 assert_se(find_executable_full("sh", NULL, NULL, false, &p, NULL) == 0);
361 puts(p);
362 assert_se(streq(basename(p), "sh"));
363 free(p);
364
365 if (oldpath)
366 assert_se(setenv("PATH", oldpath, true) >= 0);
367
368 assert_se((fd = mkostemp_safe(fn)) >= 0);
369 assert_se(fchmod(fd, 0755) >= 0);
370
371 test_file_name = basename(fn);
372
373 assert_se(find_executable_full(test_file_name, NULL, STRV_MAKE("/doesnotexist", "/tmp", "/bin"), false, &p, NULL) == 0);
374 puts(p);
375 assert_se(streq(p, fn));
376 free(p);
377
378 (void) unlink(fn);
379 assert_se(find_executable_full(test_file_name, NULL, STRV_MAKE("/doesnotexist", "/tmp", "/bin"), false, &p, NULL) == -ENOENT);
380 }
381
382 TEST(find_executable) {
383 char *p;
384
385 assert_se(find_executable("/bin/sh", &p) == 0);
386 puts(p);
387 assert_se(path_equal(p, "/bin/sh"));
388 free(p);
389
390 assert_se(find_executable(saved_argv[0], &p) == 0);
391 puts(p);
392 assert_se(endswith(p, "/test-path-util"));
393 assert_se(path_is_absolute(p));
394 free(p);
395
396 assert_se(find_executable("sh", &p) == 0);
397 puts(p);
398 assert_se(endswith(p, "/sh"));
399 assert_se(path_is_absolute(p));
400 free(p);
401
402 assert_se(find_executable("/bin/touch", &p) == 0);
403 assert_se(streq(p, "/bin/touch"));
404 free(p);
405
406 assert_se(find_executable("touch", &p) == 0);
407 assert_se(path_is_absolute(p));
408 assert_se(streq(basename(p), "touch"));
409 free(p);
410
411 assert_se(find_executable("xxxx-xxxx", &p) == -ENOENT);
412 assert_se(find_executable("/some/dir/xxxx-xxxx", &p) == -ENOENT);
413 assert_se(find_executable("/proc/filesystems", &p) == -EACCES);
414 }
415
416 static void test_find_executable_exec_one(const char *path) {
417 _cleanup_free_ char *t = NULL;
418 _cleanup_close_ int fd = -EBADF;
419 pid_t pid;
420 int r;
421
422 r = find_executable_full(path, NULL, NULL, false, &t, &fd);
423
424 log_info_errno(r, "%s: %s → %s: %d/%m", __func__, path, t ?: "-", fd);
425
426 assert_se(fd > STDERR_FILENO);
427 assert_se(path_is_absolute(t));
428 if (path_is_absolute(path))
429 assert_se(streq(t, path));
430
431 pid = fork();
432 assert_se(pid >= 0);
433 if (pid == 0) {
434 r = fexecve_or_execve(fd, t, STRV_MAKE(t, "--version"), STRV_MAKE(NULL));
435 log_error_errno(r, "[f]execve: %m");
436 _exit(EXIT_FAILURE);
437 }
438
439 assert_se(wait_for_terminate_and_check(t, pid, WAIT_LOG) == 0);
440 }
441
442 TEST(find_executable_exec) {
443 test_find_executable_exec_one("touch");
444 test_find_executable_exec_one("/bin/touch");
445
446 _cleanup_free_ char *script = NULL;
447 assert_se(get_testdata_dir("test-path-util/script.sh", &script) >= 0);
448 test_find_executable_exec_one(script);
449 }
450
451 TEST(prefixes) {
452 static const char* const values[] = {
453 "/a/b/c/d",
454 "/a/b/c",
455 "/a/b",
456 "/a",
457 "",
458 NULL
459 };
460 unsigned i;
461 char s[PATH_MAX];
462 bool b;
463
464 i = 0;
465 PATH_FOREACH_PREFIX_MORE(s, "/a/b/c/d") {
466 log_error("---%s---", s);
467 assert_se(streq(s, values[i++]));
468 }
469 assert_se(values[i] == NULL);
470
471 i = 1;
472 PATH_FOREACH_PREFIX(s, "/a/b/c/d") {
473 log_error("---%s---", s);
474 assert_se(streq(s, values[i++]));
475 }
476 assert_se(values[i] == NULL);
477
478 i = 0;
479 PATH_FOREACH_PREFIX_MORE(s, "////a////b////c///d///////")
480 assert_se(streq(s, values[i++]));
481 assert_se(values[i] == NULL);
482
483 i = 1;
484 PATH_FOREACH_PREFIX(s, "////a////b////c///d///////")
485 assert_se(streq(s, values[i++]));
486 assert_se(values[i] == NULL);
487
488 PATH_FOREACH_PREFIX(s, "////")
489 assert_not_reached();
490
491 b = false;
492 PATH_FOREACH_PREFIX_MORE(s, "////") {
493 assert_se(!b);
494 assert_se(streq(s, ""));
495 b = true;
496 }
497 assert_se(b);
498
499 PATH_FOREACH_PREFIX(s, "")
500 assert_not_reached();
501
502 b = false;
503 PATH_FOREACH_PREFIX_MORE(s, "") {
504 assert_se(!b);
505 assert_se(streq(s, ""));
506 b = true;
507 }
508 }
509
510 TEST(path_join) {
511 #define test_join(expected, ...) { \
512 _cleanup_free_ char *z = NULL; \
513 z = path_join(__VA_ARGS__); \
514 log_debug("got \"%s\", expected \"%s\"", z, expected); \
515 assert_se(streq(z, expected)); \
516 }
517
518 test_join("/root/a/b/c", "/root", "/a/b", "/c");
519 test_join("/root/a/b/c", "/root", "a/b", "c");
520 test_join("/root/a/b/c", "/root", "/a/b", "c");
521 test_join("/root/c", "/root", "/", "c");
522 test_join("/root/", "/root", "/", NULL);
523
524 test_join("/a/b/c", "", "/a/b", "/c");
525 test_join("a/b/c", "", "a/b", "c");
526 test_join("/a/b/c", "", "/a/b", "c");
527 test_join("/c", "", "/", "c");
528 test_join("/", "", "/", NULL);
529
530 test_join("/a/b/c", NULL, "/a/b", "/c");
531 test_join("a/b/c", NULL, "a/b", "c");
532 test_join("/a/b/c", NULL, "/a/b", "c");
533 test_join("/c", NULL, "/", "c");
534 test_join("/", NULL, "/", NULL);
535
536 test_join("", "", NULL);
537 test_join("", NULL, "");
538 test_join("", NULL, NULL);
539
540 test_join("foo/bar", "foo", "bar");
541 test_join("foo/bar", "", "foo", "bar");
542 test_join("foo/bar", NULL, "foo", NULL, "bar");
543 test_join("foo/bar", "", "foo", "", "bar", "");
544 test_join("foo/bar", "", "", "", "", "foo", "", "", "", "bar", "", "", "");
545
546 test_join("//foo///bar//", "", "/", "", "/foo/", "", "/", "", "/bar/", "", "/", "");
547 test_join("/foo/bar/", "/", "foo", "/", "bar", "/");
548 test_join("foo/bar/baz", "foo", "bar", "baz");
549 test_join("foo/bar/baz", "foo/", "bar", "/baz");
550 test_join("foo//bar//baz", "foo/", "/bar/", "/baz");
551 test_join("//foo////bar////baz//", "//foo/", "///bar/", "///baz//");
552 }
553
554 TEST(path_extend) {
555 _cleanup_free_ char *p = NULL;
556
557 assert_se(path_extend(&p, "foo", "bar", "baz") == p);
558 assert_se(streq(p, "foo/bar/baz"));
559
560 assert_se(path_extend(&p, "foo", "bar", "baz") == p);
561 assert_se(streq(p, "foo/bar/baz/foo/bar/baz"));
562
563 p = mfree(p);
564 assert_se(path_extend(&p, "foo") == p);
565 assert_se(streq(p, "foo"));
566
567 assert_se(path_extend(&p, "/foo") == p);
568 assert_se(streq(p, "foo/foo"));
569 assert_se(path_extend(&p, "/waaaah/wahhh//") == p);
570 assert_se(streq(p, "foo/foo/waaaah/wahhh//")); /* path_extend() does not drop redundant slashes */
571 assert_se(path_extend(&p, "/aaa/bbb/") == p);
572 assert_se(streq(p, "foo/foo/waaaah/wahhh///aaa/bbb/")); /* but not add an extra slash */
573
574 assert_se(free_and_strdup(&p, "/") >= 0);
575 assert_se(path_extend(&p, "foo") == p);
576 assert_se(streq(p, "/foo"));
577 }
578
579 TEST(fsck_exists) {
580 /* Ensure we use a sane default for PATH. */
581 assert_se(unsetenv("PATH") == 0);
582
583 /* fsck.minix is provided by util-linux and will probably exist. */
584 assert_se(fsck_exists_for_fstype("minix") == 1);
585
586 assert_se(fsck_exists_for_fstype("AbCdE") == 0);
587 assert_se(fsck_exists_for_fstype("/../bin/") == 0);
588 }
589
590 static void test_path_make_relative_one(const char *from, const char *to, const char *expected) {
591 _cleanup_free_ char *z = NULL;
592 int r;
593
594 log_info("/* %s(%s, %s) */", __func__, from, to);
595
596 r = path_make_relative(from, to, &z);
597 assert_se((r >= 0) == !!expected);
598 assert_se(streq_ptr(z, expected));
599 }
600
601 TEST(path_make_relative) {
602 test_path_make_relative_one("some/relative/path", "/some/path", NULL);
603 test_path_make_relative_one("/some/path", "some/relative/path", NULL);
604 test_path_make_relative_one("/some/dotdot/../path", "/some/path", NULL);
605
606 test_path_make_relative_one("/", "/", ".");
607 test_path_make_relative_one("/", "/some/path", "some/path");
608 test_path_make_relative_one("/some/path", "/some/path", ".");
609 test_path_make_relative_one("/some/path", "/some/path/in/subdir", "in/subdir");
610 test_path_make_relative_one("/some/path", "/", "../..");
611 test_path_make_relative_one("/some/path", "/some/other/path", "../other/path");
612 test_path_make_relative_one("/some/path/./dot", "/some/further/path", "../../further/path");
613 test_path_make_relative_one("//extra.//.//./.slashes//./won't////fo.ol///anybody//", "/././/extra././/.slashes////ar.e/.just/././.fine///", "../../../ar.e/.just/.fine");
614 }
615
616 static void test_path_make_relative_parent_one(const char *from, const char *to, const char *expected) {
617 _cleanup_free_ char *z = NULL;
618 int r;
619
620 log_info("/* %s(%s, %s) */", __func__, from, to);
621
622 r = path_make_relative_parent(from, to, &z);
623 assert_se((r >= 0) == !!expected);
624 assert_se(streq_ptr(z, expected));
625 }
626
627 TEST(path_make_relative_parent) {
628 test_path_make_relative_parent_one("some/relative/path/hoge", "/some/path", NULL);
629 test_path_make_relative_parent_one("/some/path/hoge", "some/relative/path", NULL);
630 test_path_make_relative_parent_one("/some/dotdot/../path/hoge", "/some/path", NULL);
631 test_path_make_relative_parent_one("/", "/aaa", NULL);
632
633 test_path_make_relative_parent_one("/hoge", "/", ".");
634 test_path_make_relative_parent_one("/hoge", "/some/path", "some/path");
635 test_path_make_relative_parent_one("/some/path/hoge", "/some/path", ".");
636 test_path_make_relative_parent_one("/some/path/hoge", "/some/path/in/subdir", "in/subdir");
637 test_path_make_relative_parent_one("/some/path/hoge", "/", "../..");
638 test_path_make_relative_parent_one("/some/path/hoge", "/some/other/path", "../other/path");
639 test_path_make_relative_parent_one("/some/path/./dot/hoge", "/some/further/path", "../../further/path");
640 test_path_make_relative_parent_one("//extra.//.//./.slashes//./won't////fo.ol///anybody//hoge", "/././/extra././/.slashes////ar.e/.just/././.fine///", "../../../ar.e/.just/.fine");
641 }
642
643 TEST(path_strv_resolve) {
644 char tmp_dir[] = "/tmp/test-path-util-XXXXXX";
645 _cleanup_strv_free_ char **search_dirs = NULL;
646 _cleanup_strv_free_ char **absolute_dirs = NULL;
647
648 assert_se(mkdtemp(tmp_dir) != NULL);
649
650 search_dirs = strv_new("/dir1", "/dir2", "/dir3");
651 assert_se(search_dirs);
652 STRV_FOREACH(d, search_dirs) {
653 char *p = path_join(tmp_dir, *d);
654 assert_se(p);
655 assert_se(strv_push(&absolute_dirs, p) == 0);
656 }
657
658 assert_se(mkdir(absolute_dirs[0], 0700) == 0);
659 assert_se(mkdir(absolute_dirs[1], 0700) == 0);
660 assert_se(symlink("dir2", absolute_dirs[2]) == 0);
661
662 path_strv_resolve(search_dirs, tmp_dir);
663 assert_se(streq(search_dirs[0], "/dir1"));
664 assert_se(streq(search_dirs[1], "/dir2"));
665 assert_se(streq(search_dirs[2], "/dir2"));
666
667 assert_se(rm_rf(tmp_dir, REMOVE_ROOT|REMOVE_PHYSICAL) == 0);
668 }
669
670 static void test_path_startswith_one(const char *path, const char *prefix, const char *skipped, const char *expected) {
671 const char *p, *q;
672
673 log_debug("/* %s(%s, %s) */", __func__, path, prefix);
674
675 p = path_startswith(path, prefix);
676 assert_se(streq_ptr(p, expected));
677 if (p) {
678 q = strjoina(skipped, p);
679 assert_se(streq(q, path));
680 assert_se(p == path + strlen(skipped));
681 }
682 }
683
684 TEST(path_startswith) {
685 test_path_startswith_one("/foo/bar/barfoo/", "/foo", "/foo/", "bar/barfoo/");
686 test_path_startswith_one("/foo/bar/barfoo/", "/foo/", "/foo/", "bar/barfoo/");
687 test_path_startswith_one("/foo/bar/barfoo/", "/", "/", "foo/bar/barfoo/");
688 test_path_startswith_one("/foo/bar/barfoo/", "////", "/", "foo/bar/barfoo/");
689 test_path_startswith_one("/foo/bar/barfoo/", "/foo//bar/////barfoo///", "/foo/bar/barfoo/", "");
690 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfoo////", "/foo/bar/barfoo/", "");
691 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar///barfoo/", "/foo/bar/barfoo/", "");
692 test_path_startswith_one("/foo/bar/barfoo/", "/foo////bar/barfoo/", "/foo/bar/barfoo/", "");
693 test_path_startswith_one("/foo/bar/barfoo/", "////foo/bar/barfoo/", "/foo/bar/barfoo/", "");
694 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfoo", "/foo/bar/barfoo/", "");
695
696 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo", "/foo/./", "bar///barfoo/./.");
697 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/", "/foo/./", "bar///barfoo/./.");
698 test_path_startswith_one("/foo/./bar///barfoo/./.", "/", "/", "foo/./bar///barfoo/./.");
699 test_path_startswith_one("/foo/./bar///barfoo/./.", "////", "/", "foo/./bar///barfoo/./.");
700 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo//bar/////barfoo///", "/foo/./bar///barfoo/./.", "");
701 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar/barfoo////", "/foo/./bar///barfoo/./.", "");
702 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar///barfoo/", "/foo/./bar///barfoo/./.", "");
703 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo////bar/barfoo/", "/foo/./bar///barfoo/./.", "");
704 test_path_startswith_one("/foo/./bar///barfoo/./.", "////foo/bar/barfoo/", "/foo/./bar///barfoo/./.", "");
705 test_path_startswith_one("/foo/./bar///barfoo/./.", "/foo/bar/barfoo", "/foo/./bar///barfoo/./.", "");
706
707 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa/", NULL, NULL);
708 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfooa", NULL, NULL);
709 test_path_startswith_one("/foo/bar/barfoo/", "", NULL, NULL);
710 test_path_startswith_one("/foo/bar/barfoo/", "/bar/foo", NULL, NULL);
711 test_path_startswith_one("/foo/bar/barfoo/", "/f/b/b/", NULL, NULL);
712 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/barfo", NULL, NULL);
713 test_path_startswith_one("/foo/bar/barfoo/", "/foo/bar/bar", NULL, NULL);
714 test_path_startswith_one("/foo/bar/barfoo/", "/fo", NULL, NULL);
715 }
716
717 static void test_prefix_root_one(const char *r, const char *p, const char *expected) {
718 _cleanup_free_ char *s = NULL;
719 const char *t;
720
721 assert_se(s = path_join(r, p));
722 assert_se(path_equal_ptr(s, expected));
723
724 t = prefix_roota(r, p);
725 assert_se(t);
726 assert_se(path_equal_ptr(t, expected));
727 }
728
729 TEST(prefix_root) {
730 test_prefix_root_one("/", "/foo", "/foo");
731 test_prefix_root_one(NULL, "/foo", "/foo");
732 test_prefix_root_one("", "/foo", "/foo");
733 test_prefix_root_one("///", "/foo", "/foo");
734 test_prefix_root_one("/", "////foo", "/foo");
735 test_prefix_root_one(NULL, "////foo", "/foo");
736 test_prefix_root_one("/", "foo", "/foo");
737 test_prefix_root_one("", "foo", "foo");
738 test_prefix_root_one(NULL, "foo", "foo");
739
740 test_prefix_root_one("/foo", "/bar", "/foo/bar");
741 test_prefix_root_one("/foo", "bar", "/foo/bar");
742 test_prefix_root_one("foo", "bar", "foo/bar");
743 test_prefix_root_one("/foo/", "/bar", "/foo/bar");
744 test_prefix_root_one("/foo/", "//bar", "/foo/bar");
745 test_prefix_root_one("/foo///", "//bar", "/foo/bar");
746 }
747
748 TEST(file_in_same_dir) {
749 char *t;
750
751 assert_se(file_in_same_dir("/", "a", &t) == -EADDRNOTAVAIL);
752
753 assert_se(file_in_same_dir("/", "/a", &t) >= 0);
754 assert_se(streq(t, "/a"));
755 free(t);
756
757 assert_se(file_in_same_dir("", "a", &t) == -EINVAL);
758
759 assert_se(file_in_same_dir("a/", "x", &t) >= 0);
760 assert_se(streq(t, "x"));
761 free(t);
762
763 assert_se(file_in_same_dir("bar/foo", "bar", &t) >= 0);
764 assert_se(streq(t, "bar/bar"));
765 free(t);
766 }
767
768 static void test_path_find_first_component_one(
769 const char *path,
770 bool accept_dot_dot,
771 char **expected,
772 int ret) {
773
774 log_debug("/* %s(\"%s\", accept_dot_dot=%s) */", __func__, strnull(path), yes_no(accept_dot_dot));
775
776 for (const char *p = path;;) {
777 const char *e;
778 int r;
779
780 r = path_find_first_component(&p, accept_dot_dot, &e);
781 if (r <= 0) {
782 if (r == 0) {
783 if (path) {
784 assert_se(p == path + strlen_ptr(path));
785 assert_se(isempty(p));
786 } else
787 assert_se(!p);
788 assert_se(!e);
789 }
790 assert_se(r == ret);
791 assert_se(strv_isempty(expected));
792 return;
793 }
794
795 assert_se(e);
796 assert_se(strcspn(e, "/") == (size_t) r);
797 assert_se(strlen_ptr(*expected) == (size_t) r);
798 assert_se(strneq(e, *expected++, r));
799
800 assert_se(p);
801 log_debug("p=%s", p);
802 if (!isempty(*expected))
803 assert_se(startswith(p, *expected));
804 else if (ret >= 0) {
805 assert_se(p == path + strlen_ptr(path));
806 assert_se(isempty(p));
807 }
808 }
809 }
810
811 TEST(path_find_first_component) {
812 _cleanup_free_ char *hoge = NULL;
813 char foo[NAME_MAX * 2];
814
815 test_path_find_first_component_one(NULL, false, NULL, 0);
816 test_path_find_first_component_one("", false, NULL, 0);
817 test_path_find_first_component_one("/", false, NULL, 0);
818 test_path_find_first_component_one(".", false, NULL, 0);
819 test_path_find_first_component_one("./", false, NULL, 0);
820 test_path_find_first_component_one("./.", false, NULL, 0);
821 test_path_find_first_component_one("..", false, NULL, -EINVAL);
822 test_path_find_first_component_one("/..", false, NULL, -EINVAL);
823 test_path_find_first_component_one("./..", false, NULL, -EINVAL);
824 test_path_find_first_component_one("////./././//.", false, NULL, 0);
825 test_path_find_first_component_one("a/b/c", false, STRV_MAKE("a", "b", "c"), 0);
826 test_path_find_first_component_one("././//.///aa/bbb//./ccc", false, STRV_MAKE("aa", "bbb", "ccc"), 0);
827 test_path_find_first_component_one("././//.///aa/.../../bbb//./ccc/.", false, STRV_MAKE("aa", "..."), -EINVAL);
828 test_path_find_first_component_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", false, STRV_MAKE("aaa", ".bbb"), -EINVAL);
829 test_path_find_first_component_one("a/foo./b//././/", false, STRV_MAKE("a", "foo.", "b"), 0);
830
831 test_path_find_first_component_one(NULL, true, NULL, 0);
832 test_path_find_first_component_one("", true, NULL, 0);
833 test_path_find_first_component_one("/", true, NULL, 0);
834 test_path_find_first_component_one(".", true, NULL, 0);
835 test_path_find_first_component_one("./", true, NULL, 0);
836 test_path_find_first_component_one("./.", true, NULL, 0);
837 test_path_find_first_component_one("..", true, STRV_MAKE(".."), 0);
838 test_path_find_first_component_one("/..", true, STRV_MAKE(".."), 0);
839 test_path_find_first_component_one("./..", true, STRV_MAKE(".."), 0);
840 test_path_find_first_component_one("////./././//.", true, NULL, 0);
841 test_path_find_first_component_one("a/b/c", true, STRV_MAKE("a", "b", "c"), 0);
842 test_path_find_first_component_one("././//.///aa/bbb//./ccc", true, STRV_MAKE("aa", "bbb", "ccc"), 0);
843 test_path_find_first_component_one("././//.///aa/.../../bbb//./ccc/.", true, STRV_MAKE("aa", "...", "..", "bbb", "ccc"), 0);
844 test_path_find_first_component_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", true, STRV_MAKE("aaa", ".bbb", "..", "c.", "d.dd", "..eeee"), 0);
845 test_path_find_first_component_one("a/foo./b//././/", true, STRV_MAKE("a", "foo.", "b"), 0);
846
847 memset(foo, 'a', sizeof(foo) -1);
848 char_array_0(foo);
849
850 test_path_find_first_component_one(foo, false, NULL, -EINVAL);
851 test_path_find_first_component_one(foo, true, NULL, -EINVAL);
852
853 hoge = strjoin("a/b/c/", foo, "//d/e/.//f/");
854 assert_se(hoge);
855
856 test_path_find_first_component_one(hoge, false, STRV_MAKE("a", "b", "c"), -EINVAL);
857 test_path_find_first_component_one(hoge, true, STRV_MAKE("a", "b", "c"), -EINVAL);
858 }
859
860 static void test_path_find_last_component_one(
861 const char *path,
862 bool accept_dot_dot,
863 char **expected,
864 int ret) {
865
866 log_debug("/* %s(\"%s\", accept_dot_dot=%s) */", __func__, strnull(path), yes_no(accept_dot_dot));
867
868 for (const char *next = NULL;;) {
869 const char *e;
870 int r;
871
872 r = path_find_last_component(path, accept_dot_dot, &next, &e);
873 if (r <= 0) {
874 if (r == 0) {
875 assert_se(next == path);
876 assert_se(!e);
877 }
878 assert_se(r == ret);
879 assert_se(strv_isempty(expected));
880 return;
881 }
882
883 assert_se(e);
884 assert_se(strcspn(e, "/") == (size_t) r);
885 assert_se(strlen_ptr(*expected) == (size_t) r);
886 assert_se(strneq(e, *expected++, r));
887
888 assert_se(next);
889 log_debug("path=%s\nnext=%s", path, next);
890 if (!isempty(*expected)) {
891 assert_se(next < path + strlen(path));
892 assert_se(next >= path + strlen(*expected));
893 assert_se(startswith(next - strlen(*expected), *expected));
894 } else if (ret >= 0)
895 assert_se(next == path);
896 }
897 }
898
899 TEST(path_find_last_component) {
900 _cleanup_free_ char *hoge = NULL;
901 char foo[NAME_MAX * 2];
902
903 test_path_find_last_component_one(NULL, false, NULL, 0);
904 test_path_find_last_component_one("", false, NULL, 0);
905 test_path_find_last_component_one("/", false, NULL, 0);
906 test_path_find_last_component_one(".", false, NULL, 0);
907 test_path_find_last_component_one("./", false, NULL, 0);
908 test_path_find_last_component_one("./.", false, NULL, 0);
909 test_path_find_last_component_one("..", false, NULL, -EINVAL);
910 test_path_find_last_component_one("/..", false, NULL, -EINVAL);
911 test_path_find_last_component_one("./..", false, NULL, -EINVAL);
912 test_path_find_last_component_one("////./././//.", false, NULL, 0);
913 test_path_find_last_component_one("a/b/c", false, STRV_MAKE("c", "b", "a"), 0);
914 test_path_find_last_component_one("././//.///aa./.bbb//./ccc/././/", false, STRV_MAKE("ccc", ".bbb", "aa."), 0);
915 test_path_find_last_component_one("././//.///aa/../.../bbb//./ccc/.", false, STRV_MAKE("ccc", "bbb", "..."), -EINVAL);
916 test_path_find_last_component_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", false, STRV_MAKE("..eeee", "d.dd", "c."), -EINVAL);
917
918 test_path_find_last_component_one(NULL, true, NULL, 0);
919 test_path_find_last_component_one("", true, NULL, 0);
920 test_path_find_last_component_one("/", true, NULL, 0);
921 test_path_find_last_component_one(".", true, NULL, 0);
922 test_path_find_last_component_one("./", true, NULL, 0);
923 test_path_find_last_component_one("./.", true, NULL, 0);
924 test_path_find_last_component_one("..", true, STRV_MAKE(".."), 0);
925 test_path_find_last_component_one("/..", true, STRV_MAKE(".."), 0);
926 test_path_find_last_component_one("./..", true, STRV_MAKE(".."), 0);
927 test_path_find_last_component_one("////./././//.", true, NULL, 0);
928 test_path_find_last_component_one("a/b/c", true, STRV_MAKE("c", "b", "a"), 0);
929 test_path_find_last_component_one("././//.///aa./.bbb//./ccc/././/", true, STRV_MAKE("ccc", ".bbb", "aa."), 0);
930 test_path_find_last_component_one("././//.///aa/../.../bbb//./ccc/.", true, STRV_MAKE("ccc", "bbb", "...", "..", "aa"), 0);
931 test_path_find_last_component_one("//./aaa///.//./.bbb/..///c.//d.dd///..eeee/.", true, STRV_MAKE("..eeee", "d.dd", "c.", "..", ".bbb", "aaa"), 0);
932
933 memset(foo, 'a', sizeof(foo) -1);
934 char_array_0(foo);
935
936 test_path_find_last_component_one(foo, false, NULL, -EINVAL);
937 test_path_find_last_component_one(foo, true, NULL, -EINVAL);
938
939 hoge = strjoin(foo, "/a/b/c/");
940 assert_se(hoge);
941
942 test_path_find_last_component_one(hoge, false, STRV_MAKE("c", "b", "a"), -EINVAL);
943 test_path_find_last_component_one(hoge, true, STRV_MAKE("c", "b", "a"), -EINVAL);
944 }
945
946 TEST(last_path_component) {
947 assert_se(last_path_component(NULL) == NULL);
948 assert_se(streq(last_path_component("a/b/c"), "c"));
949 assert_se(streq(last_path_component("a/b/c/"), "c/"));
950 assert_se(streq(last_path_component("/"), "/"));
951 assert_se(streq(last_path_component("//"), "/"));
952 assert_se(streq(last_path_component("///"), "/"));
953 assert_se(streq(last_path_component("."), "."));
954 assert_se(streq(last_path_component("./."), "."));
955 assert_se(streq(last_path_component("././"), "./"));
956 assert_se(streq(last_path_component("././/"), ".//"));
957 assert_se(streq(last_path_component("/foo/a"), "a"));
958 assert_se(streq(last_path_component("/foo/a/"), "a/"));
959 assert_se(streq(last_path_component(""), ""));
960 assert_se(streq(last_path_component("a"), "a"));
961 assert_se(streq(last_path_component("a/"), "a/"));
962 assert_se(streq(last_path_component("/a"), "a"));
963 assert_se(streq(last_path_component("/a/"), "a/"));
964 }
965
966 static void test_path_extract_filename_one(const char *input, const char *output, int ret) {
967 _cleanup_free_ char *k = NULL;
968 int r;
969
970 r = path_extract_filename(input, &k);
971 log_info("%s → %s/%s [expected: %s/%s]",
972 strnull(input),
973 strnull(k), r < 0 ? STRERROR(r) : "-",
974 strnull(output), ret < 0 ? STRERROR(ret) : "-");
975 assert_se(streq_ptr(k, output));
976 assert_se(r == ret);
977 }
978
979 TEST(path_extract_filename) {
980 test_path_extract_filename_one(NULL, NULL, -EINVAL);
981 test_path_extract_filename_one("a/b/c", "c", 0);
982 test_path_extract_filename_one("a/b/c/", "c", O_DIRECTORY);
983 test_path_extract_filename_one("/", NULL, -EADDRNOTAVAIL);
984 test_path_extract_filename_one("//", NULL, -EADDRNOTAVAIL);
985 test_path_extract_filename_one("///", NULL, -EADDRNOTAVAIL);
986 test_path_extract_filename_one("/.", NULL, -EADDRNOTAVAIL);
987 test_path_extract_filename_one(".", NULL, -EADDRNOTAVAIL);
988 test_path_extract_filename_one("./", NULL, -EADDRNOTAVAIL);
989 test_path_extract_filename_one("./.", NULL, -EADDRNOTAVAIL);
990 test_path_extract_filename_one("././", NULL, -EADDRNOTAVAIL);
991 test_path_extract_filename_one("././/", NULL, -EADDRNOTAVAIL);
992 test_path_extract_filename_one("/foo/a", "a", 0);
993 test_path_extract_filename_one("/foo/a/", "a", O_DIRECTORY);
994 test_path_extract_filename_one("", NULL, -EINVAL);
995 test_path_extract_filename_one("a", "a", 0);
996 test_path_extract_filename_one("a/", "a", O_DIRECTORY);
997 test_path_extract_filename_one("a/././//.", "a", O_DIRECTORY);
998 test_path_extract_filename_one("/a", "a", 0);
999 test_path_extract_filename_one("/a/", "a", O_DIRECTORY);
1000 test_path_extract_filename_one("/a//./.", "a", O_DIRECTORY);
1001 test_path_extract_filename_one("/////////////a/////////////", "a", O_DIRECTORY);
1002 test_path_extract_filename_one("//./a/.///b./././.c//./d//.", "d", O_DIRECTORY);
1003 test_path_extract_filename_one("xx/.", "xx", O_DIRECTORY);
1004 test_path_extract_filename_one("xx/..", NULL, -EINVAL);
1005 test_path_extract_filename_one("..", NULL, -EINVAL);
1006 test_path_extract_filename_one("/..", NULL, -EINVAL);
1007 test_path_extract_filename_one("../", NULL, -EINVAL);
1008 }
1009
1010 static void test_path_extract_directory_one(const char *input, const char *output, int ret) {
1011 _cleanup_free_ char *k = NULL;
1012 int r;
1013
1014 r = path_extract_directory(input, &k);
1015 log_info("%s → %s/%s [expected: %s/%s]",
1016 strnull(input),
1017 strnull(k), r < 0 ? STRERROR(r) : "-",
1018 strnull(output), STRERROR(ret));
1019 assert_se(streq_ptr(k, output));
1020 assert_se(r == ret);
1021
1022 /* Extra safety check: let's make sure that if we split out the filename too (and it works) the
1023 * joined parts are identical to the original again */
1024 if (r >= 0) {
1025 _cleanup_free_ char *f = NULL;
1026
1027 r = path_extract_filename(input, &f);
1028 if (r >= 0) {
1029 _cleanup_free_ char *j = NULL;
1030
1031 assert_se(j = path_join(k, f));
1032 assert_se(path_equal(input, j));
1033 }
1034 }
1035 }
1036
1037 TEST(path_extract_directory) {
1038 test_path_extract_directory_one(NULL, NULL, -EINVAL);
1039 test_path_extract_directory_one("a/b/c", "a/b", 0);
1040 test_path_extract_directory_one("a/b/c/", "a/b", 0);
1041 test_path_extract_directory_one("/", NULL, -EADDRNOTAVAIL);
1042 test_path_extract_directory_one("//", NULL, -EADDRNOTAVAIL);
1043 test_path_extract_directory_one("///", NULL, -EADDRNOTAVAIL);
1044 test_path_extract_directory_one("/.", NULL, -EADDRNOTAVAIL);
1045 test_path_extract_directory_one(".", NULL, -EADDRNOTAVAIL);
1046 test_path_extract_directory_one("./", NULL, -EADDRNOTAVAIL);
1047 test_path_extract_directory_one("./.", NULL, -EADDRNOTAVAIL);
1048 test_path_extract_directory_one("././", NULL, -EADDRNOTAVAIL);
1049 test_path_extract_directory_one("././/", NULL, -EADDRNOTAVAIL);
1050 test_path_extract_directory_one("/foo/a", "/foo", 0);
1051 test_path_extract_directory_one("/foo/a/", "/foo", 0);
1052 test_path_extract_directory_one("", NULL, -EINVAL);
1053 test_path_extract_directory_one("a", NULL, -EDESTADDRREQ);
1054 test_path_extract_directory_one("a/", NULL, -EDESTADDRREQ);
1055 test_path_extract_directory_one("a/././//.", NULL, -EDESTADDRREQ);
1056 test_path_extract_directory_one("/a", "/", 0);
1057 test_path_extract_directory_one("/a/", "/", 0);
1058 test_path_extract_directory_one("/a//./.", "/", 0);
1059 test_path_extract_directory_one("/////////////a/////////////", "/", 0);
1060 test_path_extract_directory_one("//./a/.///b./././.c//./d//.", "/a/b./.c", 0);
1061 test_path_extract_directory_one("xx/.", NULL, -EDESTADDRREQ);
1062 test_path_extract_directory_one("xx/..", NULL, -EINVAL);
1063 test_path_extract_directory_one("..", NULL, -EINVAL);
1064 test_path_extract_directory_one("/..", NULL, -EINVAL);
1065 test_path_extract_directory_one("../", NULL, -EINVAL);
1066 }
1067
1068 TEST(filename_is_valid) {
1069 char foo[NAME_MAX+2];
1070
1071 assert_se(!filename_is_valid(""));
1072 assert_se(!filename_is_valid("/bar/foo"));
1073 assert_se(!filename_is_valid("/"));
1074 assert_se(!filename_is_valid("."));
1075 assert_se(!filename_is_valid(".."));
1076 assert_se(!filename_is_valid("bar/foo"));
1077 assert_se(!filename_is_valid("bar/foo/"));
1078 assert_se(!filename_is_valid("bar//"));
1079
1080 memset(foo, 'a', sizeof(foo) - 1);
1081 char_array_0(foo);
1082
1083 assert_se(!filename_is_valid(foo));
1084
1085 assert_se(filename_is_valid("foo_bar-333"));
1086 assert_se(filename_is_valid("o.o"));
1087 }
1088
1089 static void test_path_is_valid_and_safe_one(const char *p, bool ret) {
1090 log_debug("/* %s(\"%s\") */", __func__, strnull(p));
1091
1092 assert_se(path_is_valid(p) == ret);
1093 if (ret)
1094 ret = !streq(p, "..") &&
1095 !startswith(p, "../") &&
1096 !endswith(p, "/..") &&
1097 !strstr(p, "/../");
1098 assert_se(path_is_safe(p) == ret);
1099 }
1100
1101 TEST(path_is_valid_and_safe) {
1102 char foo[PATH_MAX+2];
1103 const char *c;
1104
1105 test_path_is_valid_and_safe_one("", false);
1106 test_path_is_valid_and_safe_one("/bar/foo", true);
1107 test_path_is_valid_and_safe_one("/bar/foo/", true);
1108 test_path_is_valid_and_safe_one("/bar/foo/", true);
1109 test_path_is_valid_and_safe_one("//bar//foo//", true);
1110 test_path_is_valid_and_safe_one("/", true);
1111 test_path_is_valid_and_safe_one("/////", true);
1112 test_path_is_valid_and_safe_one("/////.///.////...///..//.", true);
1113 test_path_is_valid_and_safe_one(".", true);
1114 test_path_is_valid_and_safe_one("..", true);
1115 test_path_is_valid_and_safe_one("bar/foo", true);
1116 test_path_is_valid_and_safe_one("bar/foo/", true);
1117 test_path_is_valid_and_safe_one("bar//", true);
1118
1119 memset(foo, 'a', sizeof(foo) -1);
1120 char_array_0(foo);
1121
1122 test_path_is_valid_and_safe_one(foo, false);
1123
1124 c = strjoina("/xxx/", foo, "/yyy");
1125 test_path_is_valid_and_safe_one(c, false);
1126
1127 test_path_is_valid_and_safe_one("foo_bar-333", true);
1128 test_path_is_valid_and_safe_one("o.o", true);
1129 }
1130
1131 TEST(hidden_or_backup_file) {
1132 assert_se(hidden_or_backup_file(".hidden"));
1133 assert_se(hidden_or_backup_file("..hidden"));
1134 assert_se(!hidden_or_backup_file("hidden."));
1135
1136 assert_se(hidden_or_backup_file("backup~"));
1137 assert_se(hidden_or_backup_file(".backup~"));
1138
1139 assert_se(hidden_or_backup_file("lost+found"));
1140 assert_se(hidden_or_backup_file("aquota.user"));
1141 assert_se(hidden_or_backup_file("aquota.group"));
1142
1143 assert_se(hidden_or_backup_file("test.rpmnew"));
1144 assert_se(hidden_or_backup_file("test.dpkg-old"));
1145 assert_se(hidden_or_backup_file("test.dpkg-remove"));
1146 assert_se(hidden_or_backup_file("test.swp"));
1147
1148 assert_se(!hidden_or_backup_file("test.rpmnew."));
1149 assert_se(!hidden_or_backup_file("test.dpkg-old.foo"));
1150 }
1151
1152 TEST(skip_dev_prefix) {
1153 assert_se(streq(skip_dev_prefix("/"), "/"));
1154 assert_se(streq(skip_dev_prefix("/dev"), ""));
1155 assert_se(streq(skip_dev_prefix("/dev/"), ""));
1156 assert_se(streq(skip_dev_prefix("/dev/foo"), "foo"));
1157 assert_se(streq(skip_dev_prefix("/dev/foo/bar"), "foo/bar"));
1158 assert_se(streq(skip_dev_prefix("//dev"), ""));
1159 assert_se(streq(skip_dev_prefix("//dev//"), ""));
1160 assert_se(streq(skip_dev_prefix("/dev///foo"), "foo"));
1161 assert_se(streq(skip_dev_prefix("///dev///foo///bar"), "foo///bar"));
1162 assert_se(streq(skip_dev_prefix("//foo"), "//foo"));
1163 assert_se(streq(skip_dev_prefix("foo"), "foo"));
1164 }
1165
1166 TEST(empty_or_root) {
1167 assert_se(empty_or_root(NULL));
1168 assert_se(empty_or_root(""));
1169 assert_se(empty_or_root("/"));
1170 assert_se(empty_or_root("//"));
1171 assert_se(empty_or_root("///"));
1172 assert_se(empty_or_root("/////////////////"));
1173 assert_se(!empty_or_root("xxx"));
1174 assert_se(!empty_or_root("/xxx"));
1175 assert_se(!empty_or_root("/xxx/"));
1176 assert_se(!empty_or_root("//yy//"));
1177 }
1178
1179 TEST(path_startswith_set) {
1180 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/bar", "/zzz"), ""));
1181 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo/", "/zzz"), "bar"));
1182 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/foo", "/zzz"), "bar"));
1183 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "/", "/zzz"), "foo/bar"));
1184 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar", "/foo/quux", "", "/zzz"), NULL));
1185
1186 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/foo/bar", "/zzz"), NULL));
1187 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/foo/", "/zzz"), "bar2"));
1188 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/foo", "/zzz"), "bar2"));
1189 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "/", "/zzz"), "foo/bar2"));
1190 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo/bar2", "/foo/quux", "", "/zzz"), NULL));
1191
1192 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/foo/bar", "/zzz"), NULL));
1193 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/foo/", "/zzz"), NULL));
1194 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/foo", "/zzz"), NULL));
1195 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "/", "/zzz"), "foo2/bar"));
1196 assert_se(streq_ptr(PATH_STARTSWITH_SET("/foo2/bar", "/foo/quux", "", "/zzz"), NULL));
1197 }
1198
1199 TEST(path_startswith_strv) {
1200 assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/foo/bar", "/zzz")), ""));
1201 assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/foo/", "/zzz")), "bar"));
1202 assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/foo", "/zzz")), "bar"));
1203 assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "/", "/zzz")), "foo/bar"));
1204 assert_se(streq_ptr(path_startswith_strv("/foo/bar", STRV_MAKE("/foo/quux", "", "/zzz")), NULL));
1205
1206 assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/foo/bar", "/zzz")), NULL));
1207 assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/foo/", "/zzz")), "bar2"));
1208 assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/foo", "/zzz")), "bar2"));
1209 assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "/", "/zzz")), "foo/bar2"));
1210 assert_se(streq_ptr(path_startswith_strv("/foo/bar2", STRV_MAKE("/foo/quux", "", "/zzz")), NULL));
1211
1212 assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/foo/bar", "/zzz")), NULL));
1213 assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/foo/", "/zzz")), NULL));
1214 assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/foo", "/zzz")), NULL));
1215 assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "/", "/zzz")), "foo2/bar"));
1216 assert_se(streq_ptr(path_startswith_strv("/foo2/bar", STRV_MAKE("/foo/quux", "", "/zzz")), NULL));
1217 }
1218
1219 static void test_path_glob_can_match_one(const char *pattern, const char *prefix, const char *expected) {
1220 _cleanup_free_ char *result = NULL;
1221
1222 log_debug("%s(%s, %s, %s)", __func__, pattern, prefix, strnull(expected));
1223
1224 assert_se(path_glob_can_match(pattern, prefix, &result) == !!expected);
1225 assert_se(streq_ptr(result, expected));
1226 }
1227
1228 TEST(path_glob_can_match) {
1229 test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge/aaa/bbb", NULL);
1230 test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge/aaa", "/foo/hoge/aaa");
1231 test_path_glob_can_match_one("/foo/hoge/aaa", "/foo/hoge", "/foo/hoge/aaa");
1232 test_path_glob_can_match_one("/foo/hoge/aaa", "/foo", "/foo/hoge/aaa");
1233 test_path_glob_can_match_one("/foo/hoge/aaa", "/", "/foo/hoge/aaa");
1234
1235 test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge/aaa/bbb", NULL);
1236 test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge/aaa", "/foo/hoge/aaa");
1237 test_path_glob_can_match_one("/foo/*/aaa", "/foo/hoge", "/foo/hoge/aaa");
1238 test_path_glob_can_match_one("/foo/*/aaa", "/foo", "/foo/*/aaa");
1239 test_path_glob_can_match_one("/foo/*/aaa", "/", "/foo/*/aaa");
1240
1241 test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy/aaa/bbb", NULL);
1242 test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy/aaa", "/foo/xxx/yyy/aaa");
1243 test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx/yyy", "/foo/xxx/yyy/aaa");
1244 test_path_glob_can_match_one("/foo/*/*/aaa", "/foo/xxx", "/foo/xxx/*/aaa");
1245 test_path_glob_can_match_one("/foo/*/*/aaa", "/foo", "/foo/*/*/aaa");
1246 test_path_glob_can_match_one("/foo/*/*/aaa", "/", "/foo/*/*/aaa");
1247
1248 test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa/bbb/ccc", NULL);
1249 test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa/bbb", "/foo/xxx/aaa/bbb");
1250 test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/ccc", NULL);
1251 test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx/aaa", "/foo/xxx/aaa/*");
1252 test_path_glob_can_match_one("/foo/*/aaa/*", "/foo/xxx", "/foo/xxx/aaa/*");
1253 test_path_glob_can_match_one("/foo/*/aaa/*", "/foo", "/foo/*/aaa/*");
1254 test_path_glob_can_match_one("/foo/*/aaa/*", "/", "/foo/*/aaa/*");
1255 }
1256
1257 TEST(print_MAX) {
1258 log_info("PATH_MAX=%zu\n"
1259 "FILENAME_MAX=%zu\n"
1260 "NAME_MAX=%zu",
1261 (size_t) PATH_MAX,
1262 (size_t) FILENAME_MAX,
1263 (size_t) NAME_MAX);
1264
1265 assert_cc(FILENAME_MAX == PATH_MAX);
1266 }
1267
1268 DEFINE_TEST_MAIN(LOG_DEBUG);