]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/test/test-fs-util.c
tree-wide: various ubsan zero size memory fixes
[thirdparty/systemd.git] / src / test / test-fs-util.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
c270684a
RC
2
3#include <unistd.h>
4
5#include "alloc-util.h"
c270684a 6#include "fd-util.h"
1ed34d75 7#include "fd-util.h"
d944dc95 8#include "fileio.h"
c270684a 9#include "fs-util.h"
1ed34d75 10#include "id128-util.h"
c270684a
RC
11#include "macro.h"
12#include "mkdir.h"
d944dc95 13#include "path-util.h"
c270684a 14#include "rm-rf.h"
1ed34d75 15#include "stdio-util.h"
c270684a
RC
16#include "string-util.h"
17#include "strv.h"
27964854 18#include "tests.h"
f14f1806 19#include "user-util.h"
c270684a 20#include "util.h"
9590065f 21#include "virt.h"
c270684a 22
27964854
ZJS
23static const char *arg_test_dir = NULL;
24
d944dc95 25static void test_chase_symlinks(void) {
c9825701 26 _cleanup_free_ char *result = NULL;
27964854 27 char *temp;
b12d25a8 28 const char *top, *p, *pslash, *q, *qslash;
1f56e4ce 29 struct stat st;
1ed34d75 30 int r, pfd;
d944dc95 31
27964854
ZJS
32 log_info("/* %s */", __func__);
33
34 temp = strjoina(arg_test_dir ?: "/tmp", "/test-chase.XXXXXX");
d944dc95
LP
35 assert_se(mkdtemp(temp));
36
37 top = strjoina(temp, "/top");
38 assert_se(mkdir(top, 0700) >= 0);
39
40 p = strjoina(top, "/dot");
27964854
ZJS
41 if (symlink(".", p) < 0) {
42 assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM));
43 log_tests_skipped_errno(errno, "symlink() not possible");
44 goto cleanup;
45 };
d944dc95
LP
46
47 p = strjoina(top, "/dotdot");
48 assert_se(symlink("..", p) >= 0);
49
50 p = strjoina(top, "/dotdota");
51 assert_se(symlink("../a", p) >= 0);
52
53 p = strjoina(temp, "/a");
54 assert_se(symlink("b", p) >= 0);
55
56 p = strjoina(temp, "/b");
57 assert_se(symlink("/usr", p) >= 0);
58
59 p = strjoina(temp, "/start");
60 assert_se(symlink("top/dot/dotdota", p) >= 0);
61
df878e68
ZJS
62 /* Paths that use symlinks underneath the "root" */
63
c4f4fce7 64 r = chase_symlinks(p, NULL, 0, &result);
a9fb0867 65 assert_se(r > 0);
d944dc95 66 assert_se(path_equal(result, "/usr"));
b12d25a8 67 result = mfree(result);
d944dc95 68
b12d25a8
ZJS
69 pslash = strjoina(p, "/");
70 r = chase_symlinks(pslash, NULL, 0, &result);
71 assert_se(r > 0);
72 assert_se(path_equal(result, "/usr/"));
d944dc95 73 result = mfree(result);
b12d25a8 74
c4f4fce7 75 r = chase_symlinks(p, temp, 0, &result);
d944dc95
LP
76 assert_se(r == -ENOENT);
77
b12d25a8
ZJS
78 r = chase_symlinks(pslash, temp, 0, &result);
79 assert_se(r == -ENOENT);
80
d944dc95 81 q = strjoina(temp, "/usr");
a9fb0867 82
cb638b5e 83 r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
a9fb0867
LP
84 assert_se(r == 0);
85 assert_se(path_equal(result, q));
b12d25a8 86 result = mfree(result);
a9fb0867 87
b12d25a8 88 qslash = strjoina(q, "/");
d944dc95 89
b12d25a8
ZJS
90 r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
91 assert_se(r == 0);
92 assert_se(path_equal(result, qslash));
f4b85a0f 93 result = mfree(result);
b12d25a8
ZJS
94
95 assert_se(mkdir(q, 0700) >= 0);
96
c4f4fce7 97 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 98 assert_se(r > 0);
d944dc95 99 assert_se(path_equal(result, q));
b12d25a8
ZJS
100 result = mfree(result);
101
102 r = chase_symlinks(pslash, temp, 0, &result);
103 assert_se(r > 0);
104 assert_se(path_equal(result, qslash));
105 result = mfree(result);
d944dc95
LP
106
107 p = strjoina(temp, "/slash");
108 assert_se(symlink("/", p) >= 0);
109
c4f4fce7 110 r = chase_symlinks(p, NULL, 0, &result);
a9fb0867 111 assert_se(r > 0);
d944dc95 112 assert_se(path_equal(result, "/"));
d944dc95 113 result = mfree(result);
b12d25a8 114
c4f4fce7 115 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 116 assert_se(r > 0);
d944dc95 117 assert_se(path_equal(result, temp));
b12d25a8 118 result = mfree(result);
d944dc95 119
df878e68
ZJS
120 /* Paths that would "escape" outside of the "root" */
121
122 p = strjoina(temp, "/6dots");
123 assert_se(symlink("../../..", p) >= 0);
124
c4f4fce7 125 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 126 assert_se(r > 0 && path_equal(result, temp));
b12d25a8 127 result = mfree(result);
df878e68
ZJS
128
129 p = strjoina(temp, "/6dotsusr");
130 assert_se(symlink("../../../usr", p) >= 0);
131
c4f4fce7 132 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 133 assert_se(r > 0 && path_equal(result, q));
b12d25a8 134 result = mfree(result);
df878e68
ZJS
135
136 p = strjoina(temp, "/top/8dotsusr");
137 assert_se(symlink("../../../../usr", p) >= 0);
138
c4f4fce7 139 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 140 assert_se(r > 0 && path_equal(result, q));
b12d25a8 141 result = mfree(result);
df878e68
ZJS
142
143 /* Paths that contain repeated slashes */
144
d944dc95
LP
145 p = strjoina(temp, "/slashslash");
146 assert_se(symlink("///usr///", p) >= 0);
147
c4f4fce7 148 r = chase_symlinks(p, NULL, 0, &result);
a9fb0867 149 assert_se(r > 0);
d944dc95 150 assert_se(path_equal(result, "/usr"));
d944dc95 151 result = mfree(result);
b12d25a8 152
c4f4fce7 153 r = chase_symlinks(p, temp, 0, &result);
a9fb0867 154 assert_se(r > 0);
d944dc95 155 assert_se(path_equal(result, q));
b12d25a8 156 result = mfree(result);
d944dc95 157
df878e68
ZJS
158 /* Paths using . */
159
c4f4fce7 160 r = chase_symlinks("/etc/./.././", NULL, 0, &result);
a9fb0867 161 assert_se(r > 0);
d944dc95 162 assert_se(path_equal(result, "/"));
d944dc95 163 result = mfree(result);
b12d25a8 164
c4f4fce7 165 r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
a9fb0867 166 assert_se(r > 0 && path_equal(result, "/etc"));
d944dc95 167 result = mfree(result);
b12d25a8 168
95f35ccc
YW
169 r = chase_symlinks("/../.././//../../etc", NULL, 0, &result);
170 assert_se(r > 0);
171 assert_se(streq(result, "/etc"));
172 result = mfree(result);
173
174 r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result);
175 assert_se(r == 0);
176 assert_se(streq(result, "/test-chase.fsldajfl"));
177 result = mfree(result);
178
179 r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result);
180 assert_se(r > 0);
181 assert_se(streq(result, "/etc"));
182 result = mfree(result);
183
184 r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result);
185 assert_se(r == 0);
186 assert_se(streq(result, "/test-chase.fsldajfl"));
187 result = mfree(result);
188
c4f4fce7 189 r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
d944dc95 190 assert_se(r == -ENOTDIR);
b12d25a8 191 result = mfree(result);
d944dc95 192
df878e68
ZJS
193 /* Path that loops back to self */
194
d944dc95
LP
195 p = strjoina(temp, "/recursive-symlink");
196 assert_se(symlink("recursive-symlink", p) >= 0);
c4f4fce7 197 r = chase_symlinks(p, NULL, 0, &result);
d944dc95
LP
198 assert_se(r == -ELOOP);
199
a9fb0867
LP
200 /* Path which doesn't exist */
201
202 p = strjoina(temp, "/idontexist");
203 r = chase_symlinks(p, NULL, 0, &result);
204 assert_se(r == -ENOENT);
205
cb638b5e 206 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
207 assert_se(r == 0);
208 assert_se(path_equal(result, p));
209 result = mfree(result);
210
211 p = strjoina(temp, "/idontexist/meneither");
212 r = chase_symlinks(p, NULL, 0, &result);
213 assert_se(r == -ENOENT);
214
cb638b5e 215 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
216 assert_se(r == 0);
217 assert_se(path_equal(result, p));
218 result = mfree(result);
219
220 /* Path which doesn't exist, but contains weird stuff */
221
222 p = strjoina(temp, "/idontexist/..");
223 r = chase_symlinks(p, NULL, 0, &result);
224 assert_se(r == -ENOENT);
225
cb638b5e 226 r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
a9fb0867
LP
227 assert_se(r == -ENOENT);
228
877777d7
CCW
229 p = strjoina(temp, "/target");
230 q = strjoina(temp, "/top");
231 assert_se(symlink(q, p) >= 0);
232 p = strjoina(temp, "/target/idontexist");
233 r = chase_symlinks(p, NULL, 0, &result);
234 assert_se(r == -ENOENT);
235
f14f1806
LP
236 if (geteuid() == 0) {
237 p = strjoina(temp, "/priv1");
238 assert_se(mkdir(p, 0755) >= 0);
239
240 q = strjoina(p, "/priv2");
241 assert_se(mkdir(q, 0755) >= 0);
242
243 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
244
245 assert_se(chown(q, UID_NOBODY, GID_NOBODY) >= 0);
246 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
247
248 assert_se(chown(p, UID_NOBODY, GID_NOBODY) >= 0);
249 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
250
251 assert_se(chown(q, 0, 0) >= 0);
252 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
253
254 assert_se(rmdir(q) >= 0);
255 assert_se(symlink("/etc/passwd", q) >= 0);
256 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
257
258 assert_se(chown(p, 0, 0) >= 0);
259 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
260 }
261
1ed34d75
LP
262 p = strjoina(temp, "/machine-id-test");
263 assert_se(symlink("/usr/../etc/./machine-id", p) >= 0);
264
265 pfd = chase_symlinks(p, NULL, CHASE_OPEN, NULL);
266 if (pfd != -ENOENT) {
1ed34d75
LP
267 _cleanup_close_ int fd = -1;
268 sd_id128_t a, b;
269
270 assert_se(pfd >= 0);
271
f2324783 272 fd = fd_reopen(pfd, O_RDONLY|O_CLOEXEC);
1ed34d75 273 assert_se(fd >= 0);
1ed34d75
LP
274 safe_close(pfd);
275
276 assert_se(id128_read_fd(fd, ID128_PLAIN, &a) >= 0);
277 assert_se(sd_id128_get_machine(&b) >= 0);
278 assert_se(sd_id128_equal(a, b));
279 }
280
1f56e4ce
FB
281 /* Test CHASE_NOFOLLOW */
282
283 p = strjoina(temp, "/target");
284 q = strjoina(temp, "/symlink");
285 assert_se(symlink(p, q) >= 0);
286 pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
287 assert_se(pfd > 0);
288 assert_se(path_equal(result, q));
289 assert_se(fstat(pfd, &st) >= 0);
290 assert_se(S_ISLNK(st.st_mode));
291 result = mfree(result);
292
293 /* s1 -> s2 -> nonexistent */
294 q = strjoina(temp, "/s1");
295 assert_se(symlink("s2", q) >= 0);
296 p = strjoina(temp, "/s2");
297 assert_se(symlink("nonexistent", p) >= 0);
298 pfd = chase_symlinks(q, NULL, CHASE_OPEN|CHASE_NOFOLLOW, &result);
299 assert_se(pfd > 0);
300 assert_se(path_equal(result, q));
301 assert_se(fstat(pfd, &st) >= 0);
302 assert_se(S_ISLNK(st.st_mode));
303 result = mfree(result);
304
49eb3659
LP
305 /* Test CHASE_ONE */
306
307 p = strjoina(temp, "/start");
308 r = chase_symlinks(p, NULL, CHASE_STEP, &result);
309 assert_se(r == 0);
310 p = strjoina(temp, "/top/dot/dotdota");
311 assert_se(streq(p, result));
312 result = mfree(result);
313
314 r = chase_symlinks(p, NULL, CHASE_STEP, &result);
315 assert_se(r == 0);
316 p = strjoina(temp, "/top/./dotdota");
317 assert_se(streq(p, result));
318 result = mfree(result);
319
320 r = chase_symlinks(p, NULL, CHASE_STEP, &result);
321 assert_se(r == 0);
322 p = strjoina(temp, "/top/../a");
323 assert_se(streq(p, result));
324 result = mfree(result);
325
326 r = chase_symlinks(p, NULL, CHASE_STEP, &result);
327 assert_se(r == 0);
328 p = strjoina(temp, "/a");
329 assert_se(streq(p, result));
330 result = mfree(result);
331
332 r = chase_symlinks(p, NULL, CHASE_STEP, &result);
333 assert_se(r == 0);
334 p = strjoina(temp, "/b");
335 assert_se(streq(p, result));
336 result = mfree(result);
337
338 r = chase_symlinks(p, NULL, CHASE_STEP, &result);
339 assert_se(r == 0);
340 assert_se(streq("/usr", result));
341 result = mfree(result);
342
343 r = chase_symlinks("/usr", NULL, CHASE_STEP, &result);
344 assert_se(r > 0);
345 assert_se(streq("/usr", result));
346 result = mfree(result);
347
27964854 348 cleanup:
d944dc95
LP
349 assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
350}
351
c270684a 352static void test_unlink_noerrno(void) {
27964854 353 char *name;
c270684a
RC
354 int fd;
355
27964854
ZJS
356 log_info("/* %s */", __func__);
357
358 name = strjoina(arg_test_dir ?: "/tmp", "/test-close_nointr.XXXXXX");
646853bd 359 fd = mkostemp_safe(name);
c270684a
RC
360 assert_se(fd >= 0);
361 assert_se(close_nointr(fd) >= 0);
362
363 {
364 PROTECT_ERRNO;
365 errno = -42;
366 assert_se(unlink_noerrno(name) >= 0);
367 assert_se(errno == -42);
368 assert_se(unlink_noerrno(name) < 0);
369 assert_se(errno == -42);
370 }
371}
372
373static void test_readlink_and_make_absolute(void) {
27964854
ZJS
374 const char *tempdir, *name, *name2, *name_alias;
375 _cleanup_free_ char *r1 = NULL, *r2 = NULL, *pwd = NULL;
376
377 log_info("/* %s */", __func__);
378
379 tempdir = strjoina(arg_test_dir ?: "/tmp", "/test-readlink_and_make_absolute");
380 name = strjoina(tempdir, "/original");
381 name2 = "test-readlink_and_make_absolute/original";
382 name_alias = strjoina(arg_test_dir ?: "/tmp", "/test-readlink_and_make_absolute-alias");
c270684a 383
37c1d5e9 384 assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), MKDIR_WARN_MODE) >= 0);
c270684a
RC
385 assert_se(touch(name) >= 0);
386
27964854
ZJS
387 if (symlink(name, name_alias) < 0) {
388 assert_se(IN_SET(errno, EINVAL, ENOSYS, ENOTTY, EPERM));
389 log_tests_skipped_errno(errno, "symlink() not possible");
390 } else {
391 assert_se(readlink_and_make_absolute(name_alias, &r1) >= 0);
392 assert_se(streq(r1, name));
393 assert_se(unlink(name_alias) >= 0);
c270684a 394
27964854 395 assert_se(safe_getcwd(&pwd) >= 0);
cd76d4c2 396
27964854
ZJS
397 assert_se(chdir(tempdir) >= 0);
398 assert_se(symlink(name2, name_alias) >= 0);
399 assert_se(readlink_and_make_absolute(name_alias, &r2) >= 0);
400 assert_se(streq(r2, name));
401 assert_se(unlink(name_alias) >= 0);
c270684a 402
27964854
ZJS
403 assert_se(chdir(pwd) >= 0);
404 }
cd76d4c2 405
c270684a
RC
406 assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
407}
408
409static void test_get_files_in_directory(void) {
410 _cleanup_strv_free_ char **l = NULL, **t = NULL;
411
27964854 412 assert_se(get_files_in_directory(arg_test_dir ?: "/tmp", &l) >= 0);
c270684a
RC
413 assert_se(get_files_in_directory(".", &t) >= 0);
414 assert_se(get_files_in_directory(".", NULL) >= 0);
415}
416
34a8f081 417static void test_var_tmp(void) {
4245eb50 418 _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL;
992e8f22 419 const char *tmp_dir = NULL, *t;
34a8f081 420
27964854
ZJS
421 log_info("/* %s */", __func__);
422
992e8f22
LP
423 t = getenv("TMPDIR");
424 if (t) {
425 tmpdir_backup = strdup(t);
426 assert_se(tmpdir_backup);
427 }
34a8f081 428
4245eb50
MAP
429 t = getenv("TEMP");
430 if (t) {
431 temp_backup = strdup(t);
432 assert_se(temp_backup);
433 }
434
435 t = getenv("TMP");
436 if (t) {
437 tmp_backup = strdup(t);
438 assert_se(tmp_backup);
439 }
440
85e55d14
YW
441 assert_se(unsetenv("TMPDIR") >= 0);
442 assert_se(unsetenv("TEMP") >= 0);
443 assert_se(unsetenv("TMP") >= 0);
34a8f081 444
992e8f22
LP
445 assert_se(var_tmp_dir(&tmp_dir) >= 0);
446 assert_se(streq(tmp_dir, "/var/tmp"));
34a8f081 447
992e8f22
LP
448 assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
449 assert_se(streq(getenv("TMPDIR"), "/tmp"));
34a8f081 450
992e8f22
LP
451 assert_se(var_tmp_dir(&tmp_dir) >= 0);
452 assert_se(streq(tmp_dir, "/tmp"));
34a8f081 453
992e8f22
LP
454 assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
455 assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
34a8f081 456
992e8f22
LP
457 assert_se(var_tmp_dir(&tmp_dir) >= 0);
458 assert_se(streq(tmp_dir, "/var/tmp"));
34a8f081 459
992e8f22
LP
460 if (tmpdir_backup) {
461 assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
462 assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
34a8f081 463 }
4245eb50
MAP
464
465 if (temp_backup) {
466 assert_se(setenv("TEMP", temp_backup, true) >= 0);
467 assert_se(streq(getenv("TEMP"), temp_backup));
468 }
469
470 if (tmp_backup) {
471 assert_se(setenv("TMP", tmp_backup, true) >= 0);
472 assert_se(streq(getenv("TMP"), tmp_backup));
473 }
34a8f081
OW
474}
475
49bfc877 476static void test_dot_or_dot_dot(void) {
27964854
ZJS
477 log_info("/* %s */", __func__);
478
49bfc877
LP
479 assert_se(!dot_or_dot_dot(NULL));
480 assert_se(!dot_or_dot_dot(""));
481 assert_se(!dot_or_dot_dot("xxx"));
482 assert_se(dot_or_dot_dot("."));
483 assert_se(dot_or_dot_dot(".."));
484 assert_se(!dot_or_dot_dot(".foo"));
485 assert_se(!dot_or_dot_dot("..foo"));
486}
487
57a4359e
LP
488static void test_access_fd(void) {
489 _cleanup_(rmdir_and_freep) char *p = NULL;
490 _cleanup_close_ int fd = -1;
27964854 491 const char *a;
57a4359e 492
27964854
ZJS
493 log_info("/* %s */", __func__);
494
495 a = strjoina(arg_test_dir ?: "/tmp", "/access-fd.XXXXXX");
496 assert_se(mkdtemp_malloc(a, &p) >= 0);
57a4359e
LP
497
498 fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
499 assert_se(fd >= 0);
500
501 assert_se(access_fd(fd, R_OK) >= 0);
502 assert_se(access_fd(fd, F_OK) >= 0);
503 assert_se(access_fd(fd, W_OK) >= 0);
504
505 assert_se(fchmod(fd, 0000) >= 0);
506
507 assert_se(access_fd(fd, F_OK) >= 0);
508
509 if (geteuid() == 0) {
510 assert_se(access_fd(fd, R_OK) >= 0);
511 assert_se(access_fd(fd, W_OK) >= 0);
512 } else {
513 assert_se(access_fd(fd, R_OK) == -EACCES);
514 assert_se(access_fd(fd, W_OK) == -EACCES);
515 }
516}
517
9e3fa6e8
LP
518static void test_touch_file(void) {
519 uid_t test_uid, test_gid;
520 _cleanup_(rm_rf_physical_and_freep) char *p = NULL;
521 struct stat st;
522 const char *a;
523 usec_t test_mtime;
9590065f 524 int r;
9e3fa6e8 525
27964854
ZJS
526 log_info("/* %s */", __func__);
527
9e3fa6e8
LP
528 test_uid = geteuid() == 0 ? 65534 : getuid();
529 test_gid = geteuid() == 0 ? 65534 : getgid();
530
531 test_mtime = usec_sub_unsigned(now(CLOCK_REALTIME), USEC_PER_WEEK);
532
27964854
ZJS
533 a = strjoina(arg_test_dir ?: "/dev/shm", "/touch-file-XXXXXX");
534 assert_se(mkdtemp_malloc(a, &p) >= 0);
9e3fa6e8
LP
535
536 a = strjoina(p, "/regular");
27964854
ZJS
537 r = touch_file(a, false, test_mtime, test_uid, test_gid, 0640);
538 if (r < 0) {
539 assert_se(IN_SET(r, -EINVAL, -ENOSYS, -ENOTTY, -EPERM));
540 log_tests_skipped_errno(errno, "touch_file() not possible");
541 return;
542 }
543
9e3fa6e8
LP
544 assert_se(lstat(a, &st) >= 0);
545 assert_se(st.st_uid == test_uid);
546 assert_se(st.st_gid == test_gid);
547 assert_se(S_ISREG(st.st_mode));
548 assert_se((st.st_mode & 0777) == 0640);
549 assert_se(timespec_load(&st.st_mtim) == test_mtime);
550
551 a = strjoina(p, "/dir");
552 assert_se(mkdir(a, 0775) >= 0);
553 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
554 assert_se(lstat(a, &st) >= 0);
555 assert_se(st.st_uid == test_uid);
556 assert_se(st.st_gid == test_gid);
557 assert_se(S_ISDIR(st.st_mode));
558 assert_se((st.st_mode & 0777) == 0640);
559 assert_se(timespec_load(&st.st_mtim) == test_mtime);
560
561 a = strjoina(p, "/fifo");
562 assert_se(mkfifo(a, 0775) >= 0);
563 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
564 assert_se(lstat(a, &st) >= 0);
565 assert_se(st.st_uid == test_uid);
566 assert_se(st.st_gid == test_gid);
567 assert_se(S_ISFIFO(st.st_mode));
568 assert_se((st.st_mode & 0777) == 0640);
569 assert_se(timespec_load(&st.st_mtim) == test_mtime);
570
571 a = strjoina(p, "/sock");
572 assert_se(mknod(a, 0775 | S_IFSOCK, 0) >= 0);
573 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
574 assert_se(lstat(a, &st) >= 0);
575 assert_se(st.st_uid == test_uid);
576 assert_se(st.st_gid == test_gid);
577 assert_se(S_ISSOCK(st.st_mode));
578 assert_se((st.st_mode & 0777) == 0640);
579 assert_se(timespec_load(&st.st_mtim) == test_mtime);
580
581 if (geteuid() == 0) {
582 a = strjoina(p, "/cdev");
9590065f
YW
583 r = mknod(a, 0775 | S_IFCHR, makedev(0, 0));
584 if (r < 0 && errno == EPERM && detect_container() > 0) {
585 log_notice("Running in unprivileged container? Skipping remaining tests in %s", __func__);
586 return;
587 }
588 assert_se(r >= 0);
9e3fa6e8
LP
589 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
590 assert_se(lstat(a, &st) >= 0);
591 assert_se(st.st_uid == test_uid);
592 assert_se(st.st_gid == test_gid);
593 assert_se(S_ISCHR(st.st_mode));
594 assert_se((st.st_mode & 0777) == 0640);
595 assert_se(timespec_load(&st.st_mtim) == test_mtime);
596
597 a = strjoina(p, "/bdev");
598 assert_se(mknod(a, 0775 | S_IFBLK, makedev(0, 0)) >= 0);
599 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
600 assert_se(lstat(a, &st) >= 0);
601 assert_se(st.st_uid == test_uid);
602 assert_se(st.st_gid == test_gid);
603 assert_se(S_ISBLK(st.st_mode));
604 assert_se((st.st_mode & 0777) == 0640);
605 assert_se(timespec_load(&st.st_mtim) == test_mtime);
606 }
607
608 a = strjoina(p, "/lnk");
609 assert_se(symlink("target", a) >= 0);
610 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
611 assert_se(lstat(a, &st) >= 0);
612 assert_se(st.st_uid == test_uid);
613 assert_se(st.st_gid == test_gid);
614 assert_se(S_ISLNK(st.st_mode));
615 assert_se((st.st_mode & 0777) == 0640);
616 assert_se(timespec_load(&st.st_mtim) == test_mtime);
617}
618
43767d9d
LP
619static void test_unlinkat_deallocate(void) {
620 _cleanup_free_ char *p = NULL;
621 _cleanup_close_ int fd = -1;
622 struct stat st;
623
27964854
ZJS
624 log_info("/* %s */", __func__);
625
626 assert_se(tempfn_random_child(arg_test_dir, "unlink-deallocation", &p) >= 0);
43767d9d
LP
627
628 fd = open(p, O_WRONLY|O_CLOEXEC|O_CREAT|O_EXCL, 0600);
629 assert_se(fd >= 0);
630
631 assert_se(write(fd, "hallo\n", 6) == 6);
632
633 assert_se(fstat(fd, &st) >= 0);
634 assert_se(st.st_size == 6);
635 assert_se(st.st_blocks > 0);
636 assert_se(st.st_nlink == 1);
637
638 assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0);
639
640 assert_se(fstat(fd, &st) >= 0);
27964854
ZJS
641 assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6
642 (it worked) or 0 (we had to resort to truncation) */
43767d9d
LP
643 assert_se(st.st_blocks == 0);
644 assert_se(st.st_nlink == 0);
645}
646
11b29a96
LP
647static void test_fsync_directory_of_file(void) {
648 _cleanup_close_ int fd = -1;
649
27964854
ZJS
650 log_info("/* %s */", __func__);
651
652 fd = open_tmpfile_unlinkable(arg_test_dir, O_RDWR);
11b29a96
LP
653 assert_se(fd >= 0);
654
655 assert_se(fsync_directory_of_file(fd) >= 0);
656}
657
4a5d7761 658static void test_rename_noreplace(void) {
7158b4b3 659 static const char* const table[] = {
4a5d7761
LP
660 "/reg",
661 "/dir",
662 "/fifo",
663 "/socket",
664 "/symlink",
665 NULL
666 };
667
668 _cleanup_(rm_rf_physical_and_freep) char *z = NULL;
27964854 669 const char *j = NULL;
4a5d7761
LP
670 char **a, **b;
671
27964854
ZJS
672 log_info("/* %s */", __func__);
673
674 if (arg_test_dir)
675 j = strjoina(arg_test_dir, "/testXXXXXX");
7158b4b3 676 assert_se(mkdtemp_malloc(j, &z) >= 0);
4a5d7761
LP
677
678 j = strjoina(z, table[0]);
679 assert_se(touch(j) >= 0);
680
681 j = strjoina(z, table[1]);
682 assert_se(mkdir(j, 0777) >= 0);
683
684 j = strjoina(z, table[2]);
685 (void) mkfifo(j, 0777);
686
687 j = strjoina(z, table[3]);
688 (void) mknod(j, S_IFSOCK | 0777, 0);
689
690 j = strjoina(z, table[4]);
691 (void) symlink("foobar", j);
692
693 STRV_FOREACH(a, (char**) table) {
694 _cleanup_free_ char *x = NULL, *y = NULL;
695
696 x = strjoin(z, *a);
697 assert_se(x);
698
699 if (access(x, F_OK) < 0) {
700 assert_se(errno == ENOENT);
701 continue;
702 }
703
704 STRV_FOREACH(b, (char**) table) {
b81b9d40 705 _cleanup_free_ char *w = NULL;
4a5d7761 706
b81b9d40
YW
707 w = strjoin(w, *b);
708 assert_se(w);
709
710 if (access(w, F_OK) < 0) {
4a5d7761
LP
711 assert_se(errno == ENOENT);
712 continue;
713 }
714
b81b9d40 715 assert_se(rename_noreplace(AT_FDCWD, w, AT_FDCWD, y) == -EEXIST);
4a5d7761
LP
716 }
717
718 y = strjoin(z, "/somethingelse");
719 assert_se(y);
720
721 assert_se(rename_noreplace(AT_FDCWD, x, AT_FDCWD, y) >= 0);
722 assert_se(rename_noreplace(AT_FDCWD, y, AT_FDCWD, x) >= 0);
723 }
724}
725
c270684a 726int main(int argc, char *argv[]) {
27964854
ZJS
727 test_setup_logging(LOG_INFO);
728
729 arg_test_dir = argv[1];
730
c270684a 731 test_unlink_noerrno();
c270684a 732 test_get_files_in_directory();
496c486f 733 test_readlink_and_make_absolute();
34a8f081 734 test_var_tmp();
d944dc95 735 test_chase_symlinks();
49bfc877 736 test_dot_or_dot_dot();
57a4359e 737 test_access_fd();
9e3fa6e8 738 test_touch_file();
43767d9d 739 test_unlinkat_deallocate();
11b29a96 740 test_fsync_directory_of_file();
4a5d7761 741 test_rename_noreplace();
c270684a
RC
742
743 return 0;
744}