chiark / gitweb /
9b74a2b8cd50fdc0febc6b7d5cd19f19855c51b2
[elogind.git] / src / test / test-fs-util.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3   This file is part of systemd.
4
5   Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <unistd.h>
9
10 #include "alloc-util.h"
11 #include "fd-util.h"
12 //#include "fd-util.h"
13 #include "fileio.h"
14 #include "fs-util.h"
15 #include "id128-util.h"
16 #include "macro.h"
17 #include "mkdir.h"
18 #include "path-util.h"
19 #include "rm-rf.h"
20 #include "stdio-util.h"
21 #include "string-util.h"
22 #include "strv.h"
23 #include "user-util.h"
24 #include "util.h"
25
26 static void test_chase_symlinks(void) {
27         _cleanup_free_ char *result = NULL;
28         char temp[] = "/tmp/test-chase.XXXXXX";
29         const char *top, *p, *pslash, *q, *qslash;
30         int r, pfd;
31
32         assert_se(mkdtemp(temp));
33
34         top = strjoina(temp, "/top");
35         assert_se(mkdir(top, 0700) >= 0);
36
37         p = strjoina(top, "/dot");
38         assert_se(symlink(".", p) >= 0);
39
40         p = strjoina(top, "/dotdot");
41         assert_se(symlink("..", p) >= 0);
42
43         p = strjoina(top, "/dotdota");
44         assert_se(symlink("../a", p) >= 0);
45
46         p = strjoina(temp, "/a");
47         assert_se(symlink("b", p) >= 0);
48
49         p = strjoina(temp, "/b");
50         assert_se(symlink("/usr", p) >= 0);
51
52         p = strjoina(temp, "/start");
53         assert_se(symlink("top/dot/dotdota", p) >= 0);
54
55         /* Paths that use symlinks underneath the "root" */
56
57         r = chase_symlinks(p, NULL, 0, &result);
58         assert_se(r > 0);
59         assert_se(path_equal(result, "/usr"));
60         result = mfree(result);
61
62         pslash = strjoina(p, "/");
63         r = chase_symlinks(pslash, NULL, 0, &result);
64         assert_se(r > 0);
65         assert_se(path_equal(result, "/usr/"));
66         result = mfree(result);
67
68         r = chase_symlinks(p, temp, 0, &result);
69         assert_se(r == -ENOENT);
70
71         r = chase_symlinks(pslash, temp, 0, &result);
72         assert_se(r == -ENOENT);
73
74         q = strjoina(temp, "/usr");
75
76         r = chase_symlinks(p, temp, CHASE_NONEXISTENT, &result);
77         assert_se(r == 0);
78         assert_se(path_equal(result, q));
79         result = mfree(result);
80
81         qslash = strjoina(q, "/");
82
83         r = chase_symlinks(pslash, temp, CHASE_NONEXISTENT, &result);
84         assert_se(r == 0);
85         assert_se(path_equal(result, qslash));
86         result = mfree(result);
87
88         assert_se(mkdir(q, 0700) >= 0);
89
90         r = chase_symlinks(p, temp, 0, &result);
91         assert_se(r > 0);
92         assert_se(path_equal(result, q));
93         result = mfree(result);
94
95         r = chase_symlinks(pslash, temp, 0, &result);
96         assert_se(r > 0);
97         assert_se(path_equal(result, qslash));
98         result = mfree(result);
99
100         p = strjoina(temp, "/slash");
101         assert_se(symlink("/", p) >= 0);
102
103         r = chase_symlinks(p, NULL, 0, &result);
104         assert_se(r > 0);
105         assert_se(path_equal(result, "/"));
106         result = mfree(result);
107
108         r = chase_symlinks(p, temp, 0, &result);
109         assert_se(r > 0);
110         assert_se(path_equal(result, temp));
111         result = mfree(result);
112
113         /* Paths that would "escape" outside of the "root" */
114
115         p = strjoina(temp, "/6dots");
116         assert_se(symlink("../../..", p) >= 0);
117
118         r = chase_symlinks(p, temp, 0, &result);
119         assert_se(r > 0 && path_equal(result, temp));
120         result = mfree(result);
121
122         p = strjoina(temp, "/6dotsusr");
123         assert_se(symlink("../../../usr", p) >= 0);
124
125         r = chase_symlinks(p, temp, 0, &result);
126         assert_se(r > 0 && path_equal(result, q));
127         result = mfree(result);
128
129         p = strjoina(temp, "/top/8dotsusr");
130         assert_se(symlink("../../../../usr", p) >= 0);
131
132         r = chase_symlinks(p, temp, 0, &result);
133         assert_se(r > 0 && path_equal(result, q));
134         result = mfree(result);
135
136         /* Paths that contain repeated slashes */
137
138         p = strjoina(temp, "/slashslash");
139         assert_se(symlink("///usr///", p) >= 0);
140
141         r = chase_symlinks(p, NULL, 0, &result);
142         assert_se(r > 0);
143         assert_se(path_equal(result, "/usr"));
144         result = mfree(result);
145
146         r = chase_symlinks(p, temp, 0, &result);
147         assert_se(r > 0);
148         assert_se(path_equal(result, q));
149         result = mfree(result);
150
151         /* Paths using . */
152
153         r = chase_symlinks("/etc/./.././", NULL, 0, &result);
154         assert_se(r > 0);
155         assert_se(path_equal(result, "/"));
156         result = mfree(result);
157
158         r = chase_symlinks("/etc/./.././", "/etc", 0, &result);
159         assert_se(r > 0 && path_equal(result, "/etc"));
160         result = mfree(result);
161
162         r = chase_symlinks("/../.././//../../etc", NULL, 0, &result);
163         assert_se(r > 0);
164         assert_se(streq(result, "/etc"));
165         result = mfree(result);
166
167         r = chase_symlinks("/../.././//../../test-chase.fsldajfl", NULL, CHASE_NONEXISTENT, &result);
168         assert_se(r == 0);
169         assert_se(streq(result, "/test-chase.fsldajfl"));
170         result = mfree(result);
171
172         r = chase_symlinks("/../.././//../../etc", "/", CHASE_PREFIX_ROOT, &result);
173         assert_se(r > 0);
174         assert_se(streq(result, "/etc"));
175         result = mfree(result);
176
177         r = chase_symlinks("/../.././//../../test-chase.fsldajfl", "/", CHASE_PREFIX_ROOT|CHASE_NONEXISTENT, &result);
178         assert_se(r == 0);
179         assert_se(streq(result, "/test-chase.fsldajfl"));
180         result = mfree(result);
181
182         r = chase_symlinks("/etc/machine-id/foo", NULL, 0, &result);
183         assert_se(r == -ENOTDIR);
184         result = mfree(result);
185
186         /* Path that loops back to self */
187
188         p = strjoina(temp, "/recursive-symlink");
189         assert_se(symlink("recursive-symlink", p) >= 0);
190         r = chase_symlinks(p, NULL, 0, &result);
191         assert_se(r == -ELOOP);
192
193         /* Path which doesn't exist */
194
195         p = strjoina(temp, "/idontexist");
196         r = chase_symlinks(p, NULL, 0, &result);
197         assert_se(r == -ENOENT);
198
199         r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
200         assert_se(r == 0);
201         assert_se(path_equal(result, p));
202         result = mfree(result);
203
204         p = strjoina(temp, "/idontexist/meneither");
205         r = chase_symlinks(p, NULL, 0, &result);
206         assert_se(r == -ENOENT);
207
208         r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
209         assert_se(r == 0);
210         assert_se(path_equal(result, p));
211         result = mfree(result);
212
213         /* Path which doesn't exist, but contains weird stuff */
214
215         p = strjoina(temp, "/idontexist/..");
216         r = chase_symlinks(p, NULL, 0, &result);
217         assert_se(r == -ENOENT);
218
219         r = chase_symlinks(p, NULL, CHASE_NONEXISTENT, &result);
220         assert_se(r == -ENOENT);
221
222         p = strjoina(temp, "/target");
223         q = strjoina(temp, "/top");
224         assert_se(symlink(q, p) >= 0);
225         p = strjoina(temp, "/target/idontexist");
226         r = chase_symlinks(p, NULL, 0, &result);
227         assert_se(r == -ENOENT);
228
229         if (geteuid() == 0) {
230                 p = strjoina(temp, "/priv1");
231                 assert_se(mkdir(p, 0755) >= 0);
232
233                 q = strjoina(p, "/priv2");
234                 assert_se(mkdir(q, 0755) >= 0);
235
236                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
237
238                 assert_se(chown(q, UID_NOBODY, GID_NOBODY) >= 0);
239                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
240
241                 assert_se(chown(p, UID_NOBODY, GID_NOBODY) >= 0);
242                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
243
244                 assert_se(chown(q, 0, 0) >= 0);
245                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
246
247                 assert_se(rmdir(q) >= 0);
248                 assert_se(symlink("/etc/passwd", q) >= 0);
249                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) == -EPERM);
250
251                 assert_se(chown(p, 0, 0) >= 0);
252                 assert_se(chase_symlinks(q, NULL, CHASE_SAFE, NULL) >= 0);
253         }
254
255         p = strjoina(temp, "/machine-id-test");
256         assert_se(symlink("/usr/../etc/./machine-id", p) >= 0);
257
258         pfd = chase_symlinks(p, NULL, CHASE_OPEN, NULL);
259         if (pfd != -ENOENT) {
260                 _cleanup_close_ int fd = -1;
261                 sd_id128_t a, b;
262
263                 assert_se(pfd >= 0);
264
265                 fd = fd_reopen(pfd, O_RDONLY|O_CLOEXEC);
266                 assert_se(fd >= 0);
267                 safe_close(pfd);
268
269                 assert_se(id128_read_fd(fd, ID128_PLAIN, &a) >= 0);
270                 assert_se(sd_id128_get_machine(&b) >= 0);
271                 assert_se(sd_id128_equal(a, b));
272         }
273
274         /* Test CHASE_ONE */
275
276         p = strjoina(temp, "/start");
277         r = chase_symlinks(p, NULL, CHASE_STEP, &result);
278         assert_se(r == 0);
279         p = strjoina(temp, "/top/dot/dotdota");
280         assert_se(streq(p, result));
281         result = mfree(result);
282
283         r = chase_symlinks(p, NULL, CHASE_STEP, &result);
284         assert_se(r == 0);
285         p = strjoina(temp, "/top/./dotdota");
286         assert_se(streq(p, result));
287         result = mfree(result);
288
289         r = chase_symlinks(p, NULL, CHASE_STEP, &result);
290         assert_se(r == 0);
291         p = strjoina(temp, "/top/../a");
292         assert_se(streq(p, result));
293         result = mfree(result);
294
295         r = chase_symlinks(p, NULL, CHASE_STEP, &result);
296         assert_se(r == 0);
297         p = strjoina(temp, "/a");
298         assert_se(streq(p, result));
299         result = mfree(result);
300
301         r = chase_symlinks(p, NULL, CHASE_STEP, &result);
302         assert_se(r == 0);
303         p = strjoina(temp, "/b");
304         assert_se(streq(p, result));
305         result = mfree(result);
306
307         r = chase_symlinks(p, NULL, CHASE_STEP, &result);
308         assert_se(r == 0);
309         assert_se(streq("/usr", result));
310         result = mfree(result);
311
312         r = chase_symlinks("/usr", NULL, CHASE_STEP, &result);
313         assert_se(r > 0);
314         assert_se(streq("/usr", result));
315         result = mfree(result);
316
317         assert_se(rm_rf(temp, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
318 }
319
320 static void test_unlink_noerrno(void) {
321         char name[] = "/tmp/test-close_nointr.XXXXXX";
322         int fd;
323
324         fd = mkostemp_safe(name);
325         assert_se(fd >= 0);
326         assert_se(close_nointr(fd) >= 0);
327
328         {
329                 PROTECT_ERRNO;
330                 errno = -42;
331                 assert_se(unlink_noerrno(name) >= 0);
332                 assert_se(errno == -42);
333                 assert_se(unlink_noerrno(name) < 0);
334                 assert_se(errno == -42);
335         }
336 }
337
338 static void test_readlink_and_make_absolute(void) {
339         char tempdir[] = "/tmp/test-readlink_and_make_absolute";
340         char name[] = "/tmp/test-readlink_and_make_absolute/original";
341         char name2[] = "test-readlink_and_make_absolute/original";
342         char name_alias[] = "/tmp/test-readlink_and_make_absolute-alias";
343         char *r = NULL;
344         _cleanup_free_ char *pwd = NULL;
345
346         assert_se(mkdir_safe(tempdir, 0755, getuid(), getgid(), MKDIR_WARN_MODE) >= 0);
347         assert_se(touch(name) >= 0);
348
349         assert_se(symlink(name, name_alias) >= 0);
350         assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
351         assert_se(streq(r, name));
352         free(r);
353         assert_se(unlink(name_alias) >= 0);
354
355         assert_se(safe_getcwd(&pwd) >= 0);
356
357         assert_se(chdir(tempdir) >= 0);
358         assert_se(symlink(name2, name_alias) >= 0);
359         assert_se(readlink_and_make_absolute(name_alias, &r) >= 0);
360         assert_se(streq(r, name));
361         free(r);
362         assert_se(unlink(name_alias) >= 0);
363
364         assert_se(chdir(pwd) >= 0);
365
366         assert_se(rm_rf(tempdir, REMOVE_ROOT|REMOVE_PHYSICAL) >= 0);
367 }
368
369 static void test_get_files_in_directory(void) {
370         _cleanup_strv_free_ char **l = NULL, **t = NULL;
371
372         assert_se(get_files_in_directory("/tmp", &l) >= 0);
373         assert_se(get_files_in_directory(".", &t) >= 0);
374         assert_se(get_files_in_directory(".", NULL) >= 0);
375 }
376
377 #if 0 /// UNNEEDED by elogind
378 static void test_var_tmp(void) {
379         _cleanup_free_ char *tmpdir_backup = NULL, *temp_backup = NULL, *tmp_backup = NULL;
380         const char *tmp_dir = NULL, *t;
381
382         t = getenv("TMPDIR");
383         if (t) {
384                 tmpdir_backup = strdup(t);
385                 assert_se(tmpdir_backup);
386         }
387
388         t = getenv("TEMP");
389         if (t) {
390                 temp_backup = strdup(t);
391                 assert_se(temp_backup);
392         }
393
394         t = getenv("TMP");
395         if (t) {
396                 tmp_backup = strdup(t);
397                 assert_se(tmp_backup);
398         }
399
400         assert_se(unsetenv("TMPDIR") >= 0);
401         assert_se(unsetenv("TEMP") >= 0);
402         assert_se(unsetenv("TMP") >= 0);
403
404         assert_se(var_tmp_dir(&tmp_dir) >= 0);
405         assert_se(streq(tmp_dir, "/var/tmp"));
406
407         assert_se(setenv("TMPDIR", "/tmp", true) >= 0);
408         assert_se(streq(getenv("TMPDIR"), "/tmp"));
409
410         assert_se(var_tmp_dir(&tmp_dir) >= 0);
411         assert_se(streq(tmp_dir, "/tmp"));
412
413         assert_se(setenv("TMPDIR", "/88_does_not_exist_88", true) >= 0);
414         assert_se(streq(getenv("TMPDIR"), "/88_does_not_exist_88"));
415
416         assert_se(var_tmp_dir(&tmp_dir) >= 0);
417         assert_se(streq(tmp_dir, "/var/tmp"));
418
419         if (tmpdir_backup)  {
420                 assert_se(setenv("TMPDIR", tmpdir_backup, true) >= 0);
421                 assert_se(streq(getenv("TMPDIR"), tmpdir_backup));
422         }
423
424         if (temp_backup)  {
425                 assert_se(setenv("TEMP", temp_backup, true) >= 0);
426                 assert_se(streq(getenv("TEMP"), temp_backup));
427         }
428
429         if (tmp_backup)  {
430                 assert_se(setenv("TMP", tmp_backup, true) >= 0);
431                 assert_se(streq(getenv("TMP"), tmp_backup));
432         }
433 }
434 #endif // 0
435
436 static void test_dot_or_dot_dot(void) {
437         assert_se(!dot_or_dot_dot(NULL));
438         assert_se(!dot_or_dot_dot(""));
439         assert_se(!dot_or_dot_dot("xxx"));
440         assert_se(dot_or_dot_dot("."));
441         assert_se(dot_or_dot_dot(".."));
442         assert_se(!dot_or_dot_dot(".foo"));
443         assert_se(!dot_or_dot_dot("..foo"));
444 }
445
446 #if 0 /// Uses functions that elogind does not need
447 static void test_access_fd(void) {
448         _cleanup_(rmdir_and_freep) char *p = NULL;
449         _cleanup_close_ int fd = -1;
450
451         assert_se(mkdtemp_malloc("/tmp/access-fd.XXXXXX", &p) >= 0);
452
453         fd = open(p, O_RDONLY|O_DIRECTORY|O_CLOEXEC);
454         assert_se(fd >= 0);
455
456         assert_se(access_fd(fd, R_OK) >= 0);
457         assert_se(access_fd(fd, F_OK) >= 0);
458         assert_se(access_fd(fd, W_OK) >= 0);
459
460         assert_se(fchmod(fd, 0000) >= 0);
461
462         assert_se(access_fd(fd, F_OK) >= 0);
463
464         if (geteuid() == 0) {
465                 assert_se(access_fd(fd, R_OK) >= 0);
466                 assert_se(access_fd(fd, W_OK) >= 0);
467         } else {
468                 assert_se(access_fd(fd, R_OK) == -EACCES);
469                 assert_se(access_fd(fd, W_OK) == -EACCES);
470         }
471 }
472
473 static void test_touch_file(void) {
474         uid_t test_uid, test_gid;
475         _cleanup_(rm_rf_physical_and_freep) char *p = NULL;
476         struct stat st;
477         const char *a;
478         usec_t test_mtime;
479
480         test_uid = geteuid() == 0 ? 65534 : getuid();
481         test_gid = geteuid() == 0 ? 65534 : getgid();
482
483         test_mtime = usec_sub_unsigned(now(CLOCK_REALTIME), USEC_PER_WEEK);
484
485         assert_se(mkdtemp_malloc("/dev/shm/touch-file-XXXXXX", &p) >= 0);
486
487         a = strjoina(p, "/regular");
488         assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
489         assert_se(lstat(a, &st) >= 0);
490         assert_se(st.st_uid == test_uid);
491         assert_se(st.st_gid == test_gid);
492         assert_se(S_ISREG(st.st_mode));
493         assert_se((st.st_mode & 0777) == 0640);
494         assert_se(timespec_load(&st.st_mtim) == test_mtime);
495
496         a = strjoina(p, "/dir");
497         assert_se(mkdir(a, 0775) >= 0);
498         assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
499         assert_se(lstat(a, &st) >= 0);
500         assert_se(st.st_uid == test_uid);
501         assert_se(st.st_gid == test_gid);
502         assert_se(S_ISDIR(st.st_mode));
503         assert_se((st.st_mode & 0777) == 0640);
504         assert_se(timespec_load(&st.st_mtim) == test_mtime);
505
506         a = strjoina(p, "/fifo");
507         assert_se(mkfifo(a, 0775) >= 0);
508         assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
509         assert_se(lstat(a, &st) >= 0);
510         assert_se(st.st_uid == test_uid);
511         assert_se(st.st_gid == test_gid);
512         assert_se(S_ISFIFO(st.st_mode));
513         assert_se((st.st_mode & 0777) == 0640);
514         assert_se(timespec_load(&st.st_mtim) == test_mtime);
515
516         a = strjoina(p, "/sock");
517         assert_se(mknod(a, 0775 | S_IFSOCK, 0) >= 0);
518         assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
519         assert_se(lstat(a, &st) >= 0);
520         assert_se(st.st_uid == test_uid);
521         assert_se(st.st_gid == test_gid);
522         assert_se(S_ISSOCK(st.st_mode));
523         assert_se((st.st_mode & 0777) == 0640);
524         assert_se(timespec_load(&st.st_mtim) == test_mtime);
525
526         if (geteuid() == 0) {
527                 a = strjoina(p, "/cdev");
528                 assert_se(mknod(a, 0775 | S_IFCHR, makedev(0, 0)) >= 0);
529                 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
530                 assert_se(lstat(a, &st) >= 0);
531                 assert_se(st.st_uid == test_uid);
532                 assert_se(st.st_gid == test_gid);
533                 assert_se(S_ISCHR(st.st_mode));
534                 assert_se((st.st_mode & 0777) == 0640);
535                 assert_se(timespec_load(&st.st_mtim) == test_mtime);
536
537                 a = strjoina(p, "/bdev");
538                 assert_se(mknod(a, 0775 | S_IFBLK, makedev(0, 0)) >= 0);
539                 assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
540                 assert_se(lstat(a, &st) >= 0);
541                 assert_se(st.st_uid == test_uid);
542                 assert_se(st.st_gid == test_gid);
543                 assert_se(S_ISBLK(st.st_mode));
544                 assert_se((st.st_mode & 0777) == 0640);
545                 assert_se(timespec_load(&st.st_mtim) == test_mtime);
546         }
547
548         a = strjoina(p, "/lnk");
549         assert_se(symlink("target", a) >= 0);
550         assert_se(touch_file(a, false, test_mtime, test_uid, test_gid, 0640) >= 0);
551         assert_se(lstat(a, &st) >= 0);
552         assert_se(st.st_uid == test_uid);
553         assert_se(st.st_gid == test_gid);
554         assert_se(S_ISLNK(st.st_mode));
555         assert_se((st.st_mode & 0777) == 0640);
556         assert_se(timespec_load(&st.st_mtim) == test_mtime);
557 }
558
559 static void test_unlinkat_deallocate(void) {
560         _cleanup_free_ char *p = NULL;
561         _cleanup_close_ int fd = -1;
562         struct stat st;
563
564         assert_se(tempfn_random_child(NULL, "unlink-deallocation", &p) >= 0);
565
566         fd = open(p, O_WRONLY|O_CLOEXEC|O_CREAT|O_EXCL, 0600);
567         assert_se(fd >= 0);
568
569         assert_se(write(fd, "hallo\n", 6) == 6);
570
571         assert_se(fstat(fd, &st) >= 0);
572         assert_se(st.st_size == 6);
573         assert_se(st.st_blocks > 0);
574         assert_se(st.st_nlink == 1);
575
576         assert_se(unlinkat_deallocate(AT_FDCWD, p, 0) >= 0);
577
578         assert_se(fstat(fd, &st) >= 0);
579         assert_se(IN_SET(st.st_size, 0, 6)); /* depending on whether hole punching worked the size will be 6 (it worked) or 0 (we had to resort to truncation) */
580         assert_se(st.st_blocks == 0);
581         assert_se(st.st_nlink == 0);
582 }
583 #endif // 0
584
585 static void test_fsync_directory_of_file(void) {
586         _cleanup_close_ int fd = -1;
587
588         fd = open_tmpfile_unlinkable(NULL, O_RDWR);
589         assert_se(fd >= 0);
590
591         assert_se(fsync_directory_of_file(fd) >= 0);
592 }
593
594 int main(int argc, char *argv[]) {
595         test_unlink_noerrno();
596         test_get_files_in_directory();
597         test_readlink_and_make_absolute();
598 #if 0 /// UNNEEDED by elogind
599         test_var_tmp();
600 #endif // 0
601         test_chase_symlinks();
602         test_dot_or_dot_dot();
603 #if 0 /// Uses functions that elogind does not need
604         test_access_fd();
605         test_touch_file();
606         test_unlinkat_deallocate();
607 #endif // 0
608         test_fsync_directory_of_file();
609
610         return 0;
611 }