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