libfuse
test_syscalls.c
1#define _GNU_SOURCE
2#include "fuse_config.h"
3
4#include <stdio.h>
5#include <stdlib.h>
6#include <stdarg.h>
7#include <string.h>
8#include <unistd.h>
9#include <fcntl.h>
10#include <dirent.h>
11#include <utime.h>
12#include <errno.h>
13#include <assert.h>
14#include <time.h>
15#include <sys/socket.h>
16#include <sys/types.h>
17#include <sys/stat.h>
18#include <sys/un.h>
19
20#ifndef ALLPERMS
21# define ALLPERMS (S_ISUID|S_ISGID|S_ISVTX|S_IRWXU|S_IRWXG|S_IRWXO)/* 07777 */
22#endif
23
24
25static const char *basepath;
26static const char *basepath_r;
27static char testfile[1024];
28static char testfile2[1024];
29static char testdir[1024];
30static char testdir2[1024];
31static char testsock[1024];
32static char subfile[1280];
33
34static char testfile_r[1024];
35static char testfile2_r[1024];
36static char testdir_r[1024];
37static char testdir2_r[1024];
38static char subfile_r[1280];
39
40static char testname[256];
41static char testdata[] = "abcdefghijklmnopqrstuvwxyz";
42static char testdata2[] = "1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./";
43static const char *testdir_files[] = { "f1", "f2", NULL};
44static long seekdir_offsets[4];
45static char zerodata[4096];
46static int testdatalen = sizeof(testdata) - 1;
47static int testdata2len = sizeof(testdata2) - 1;
48static unsigned int testnum = 0;
49static unsigned int select_test = 0;
50static unsigned int skip_test = 0;
51static unsigned int unlinked_test = 0;
52
53#define MAX_ENTRIES 1024
54#define MAX_TESTS 100
55
56static struct test {
57 int fd;
58 struct stat stat;
59} tests[MAX_TESTS];
60
61static void test_perror(const char *func, const char *msg)
62{
63 fprintf(stderr, "%s %s() - %s: %s\n", testname, func, msg,
64 strerror(errno));
65}
66
67static void test_error(const char *func, const char *msg, ...)
68 __attribute__ ((format (printf, 2, 3)));
69
70static void __start_test(const char *fmt, ...)
71 __attribute__ ((format (printf, 1, 2)));
72
73static void test_error(const char *func, const char *msg, ...)
74{
75 va_list ap;
76 fprintf(stderr, "%s %s() - ", testname, func);
77 va_start(ap, msg);
78 vfprintf(stderr, msg, ap);
79 va_end(ap);
80 fprintf(stderr, "\n");
81}
82
83static int is_dot_or_dotdot(const char *name) {
84 return name[0] == '.' &&
85 (name[1] == '\0' || (name[1] == '.' && name[2] == '\0'));
86}
87
88/*
89 * Seconds since the first line this process printed. The origin is taken
90 * lazily so it needs no init call and cannot precede the first test.
91 */
92static double test_elapsed(void)
93{
94 static struct timespec start;
95 struct timespec now;
96
97 clock_gettime(CLOCK_MONOTONIC, &now);
98 if (start.tv_sec == 0 && start.tv_nsec == 0)
99 start = now;
100 return (now.tv_sec - start.tv_sec) +
101 (now.tv_nsec - start.tv_nsec) / 1e9;
102}
103
104static void success(void)
105{
106 fprintf(stderr, "+%8.3fs %s OK\n", test_elapsed(), testname);
107}
108
109#define this_test (&tests[testnum-1])
110#define next_test (&tests[testnum])
111
112static void __start_test(const char *fmt, ...)
113{
114 unsigned int n;
115 va_list ap;
116 n = sprintf(testname, "%3i [", testnum);
117 va_start(ap, fmt);
118 n += vsprintf(testname + n, fmt, ap);
119 va_end(ap);
120 sprintf(testname + n, "]");
121 // Use dedicated testfile per test
122 sprintf(testfile, "%s/testfile.%d", basepath, testnum);
123 sprintf(testfile_r, "%s/testfile.%d", basepath_r, testnum);
124 if (testnum > MAX_TESTS) {
125 fprintf(stderr, "%s - too many tests\n", testname);
126 exit(1);
127 }
128 /* A test that never finishes prints nothing otherwise, leaving the log
129 * ending at the last test that passed. stderr, so a SIGKILL cannot
130 * swallow it.
131 */
132 fprintf(stderr, "+%8.3fs %s START\n", test_elapsed(), testname);
133 this_test->fd = -1;
134}
135
136#define start_test(msg, args...) { \
137 testnum++; \
138 if ((select_test && testnum != select_test) || \
139 (testnum == skip_test)) { \
140 return 0; \
141 } \
142 __start_test(msg, ##args); \
143}
144
145#define PERROR(msg) test_perror(__FUNCTION__, msg)
146#define ERROR(msg, args...) test_error(__FUNCTION__, msg, ##args)
147
148#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
149
150static int st_check_size(struct stat *st, int len)
151{
152 if (st->st_size != len) {
153 ERROR("length %u instead of %u", (int) st->st_size,
154 (int) len);
155 return -1;
156 }
157 return 0;
158}
159
160static int check_size(const char *path, int len)
161{
162 struct stat stbuf;
163 int res = stat(path, &stbuf);
164 if (res == -1) {
165 PERROR("stat");
166 return -1;
167 }
168 return st_check_size(&stbuf, len);
169}
170
171static int check_testfile_size(const char *path, int len)
172{
173 this_test->stat.st_size = len;
174 return check_size(path, len);
175}
176
177static int st_check_type(struct stat *st, mode_t type)
178{
179 if ((st->st_mode & S_IFMT) != type) {
180 ERROR("type 0%o instead of 0%o", st->st_mode & S_IFMT, type);
181 return -1;
182 }
183 return 0;
184}
185
186static int check_type(const char *path, mode_t type)
187{
188 struct stat stbuf;
189 int res = lstat(path, &stbuf);
190 if (res == -1) {
191 PERROR("lstat");
192 return -1;
193 }
194 return st_check_type(&stbuf, type);
195}
196
197static int st_check_mode(struct stat *st, mode_t mode)
198{
199 if ((st->st_mode & ALLPERMS) != mode) {
200 ERROR("mode 0%o instead of 0%o", st->st_mode & ALLPERMS,
201 mode);
202 return -1;
203 }
204 return 0;
205}
206
207static int check_mode(const char *path, mode_t mode)
208{
209 struct stat stbuf;
210 int res = lstat(path, &stbuf);
211 if (res == -1) {
212 PERROR("lstat");
213 return -1;
214 }
215 return st_check_mode(&stbuf, mode);
216}
217
218static int check_testfile_mode(const char *path, mode_t mode)
219{
220 this_test->stat.st_mode &= ~ALLPERMS;
221 this_test->stat.st_mode |= mode;
222 return check_mode(path, mode);
223}
224
225static int check_times(const char *path, time_t atime, time_t mtime)
226{
227 int err = 0;
228 struct stat stbuf;
229 int res = lstat(path, &stbuf);
230 if (res == -1) {
231 PERROR("lstat");
232 return -1;
233 }
234 if (stbuf.st_atime != atime) {
235 ERROR("atime %li instead of %li", stbuf.st_atime, atime);
236 err--;
237 }
238 if (stbuf.st_mtime != mtime) {
239 ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime);
240 err--;
241 }
242 if (err)
243 return -1;
244
245 return 0;
246}
247
248#if 0
249static int fcheck_times(int fd, time_t atime, time_t mtime)
250{
251 int err = 0;
252 struct stat stbuf;
253 int res = fstat(fd, &stbuf);
254 if (res == -1) {
255 PERROR("fstat");
256 return -1;
257 }
258 if (stbuf.st_atime != atime) {
259 ERROR("atime %li instead of %li", stbuf.st_atime, atime);
260 err--;
261 }
262 if (stbuf.st_mtime != mtime) {
263 ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime);
264 err--;
265 }
266 if (err)
267 return -1;
268
269 return 0;
270}
271#endif
272
273static int st_check_nlink(struct stat *st, nlink_t nlink)
274{
275 if (st->st_nlink != nlink) {
276 ERROR("nlink %li instead of %li", (long) st->st_nlink,
277 (long) nlink);
278 return -1;
279 }
280 return 0;
281}
282
283static int check_nlink(const char *path, nlink_t nlink)
284{
285 struct stat stbuf;
286 int res = lstat(path, &stbuf);
287 if (res == -1) {
288 PERROR("lstat");
289 return -1;
290 }
291 return st_check_nlink(&stbuf, nlink);
292}
293
294static int fcheck_stat(int fd, int flags, struct stat *st)
295{
296 struct stat stbuf;
297 int res = fstat(fd, &stbuf);
298 if (res == -1) {
299 if (flags & O_PATH) {
300 // With O_PATH fd, the server does not have to keep
301 // the inode alive so FUSE inode may be stale or bad
302 if (errno == ESTALE || errno == EIO ||
303 errno == ENOENT || errno == EBADF)
304 return 0;
305 }
306 PERROR("fstat");
307 return -1;
308 }
309
310 int err = 0;
311 err += st_check_type(&stbuf, st->st_mode & S_IFMT);
312 err += st_check_mode(&stbuf, st->st_mode & ALLPERMS);
313 err += st_check_size(&stbuf, st->st_size);
314 err += st_check_nlink(&stbuf, st->st_nlink);
315
316 return err;
317}
318
319static int check_nonexist(const char *path)
320{
321 struct stat stbuf;
322 int res = lstat(path, &stbuf);
323 if (res == 0) {
324 ERROR("file should not exist");
325 return -1;
326 }
327 if (errno != ENOENT) {
328 ERROR("file should not exist: %s", strerror(errno));
329 return -1;
330 }
331 return 0;
332}
333
334static int check_buffer(const char *buf, const char *data, unsigned len)
335{
336 if (memcmp(buf, data, len) != 0) {
337 ERROR("data mismatch");
338 return -1;
339 }
340 return 0;
341}
342
343static int check_data(const char *path, const char *data, int offset,
344 unsigned len)
345{
346 char buf[4096];
347 int res;
348 int fd = open(path, O_RDONLY);
349 if (fd == -1) {
350 PERROR("open");
351 return -1;
352 }
353 if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
354 PERROR("lseek");
355 close(fd);
356 return -1;
357 }
358 while (len) {
359 int rdlen = len < sizeof(buf) ? len : sizeof(buf);
360 res = read(fd, buf, rdlen);
361 if (res == -1) {
362 PERROR("read");
363 close(fd);
364 return -1;
365 }
366 if (res != rdlen) {
367 ERROR("short read: %u instead of %u", res, rdlen);
368 close(fd);
369 return -1;
370 }
371 if (check_buffer(buf, data, rdlen) != 0) {
372 close(fd);
373 return -1;
374 }
375 data += rdlen;
376 len -= rdlen;
377 }
378 res = close(fd);
379 if (res == -1) {
380 PERROR("close");
381 return -1;
382 }
383 return 0;
384}
385
386static int fcheck_data(int fd, const char *data, int offset,
387 unsigned len)
388{
389 char buf[4096];
390 int res;
391 if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
392 PERROR("lseek");
393 return -1;
394 }
395 while (len) {
396 int rdlen = len < sizeof(buf) ? len : sizeof(buf);
397 res = read(fd, buf, rdlen);
398 if (res == -1) {
399 PERROR("read");
400 return -1;
401 }
402 if (res != rdlen) {
403 ERROR("short read: %u instead of %u", res, rdlen);
404 return -1;
405 }
406 if (check_buffer(buf, data, rdlen) != 0) {
407 return -1;
408 }
409 data += rdlen;
410 len -= rdlen;
411 }
412 return 0;
413}
414
415static int check_dir_contents(const char *path, const char **contents)
416{
417 int i;
418 int res;
419 int err = 0;
420 int found[MAX_ENTRIES];
421 const char *cont[MAX_ENTRIES];
422 DIR *dp;
423
424 for (i = 0; contents[i]; i++) {
425 assert(i < MAX_ENTRIES - 3);
426 found[i] = 0;
427 cont[i] = contents[i];
428 }
429 cont[i] = NULL;
430
431 dp = opendir(path);
432 if (dp == NULL) {
433 PERROR("opendir");
434 return -1;
435 }
436 memset(found, 0, sizeof(found));
437 while(1) {
438 struct dirent *de;
439 errno = 0;
440 de = readdir(dp);
441 if (de == NULL) {
442 if (errno) {
443 PERROR("readdir");
444 closedir(dp);
445 return -1;
446 }
447 break;
448 }
449 if (is_dot_or_dotdot(de->d_name))
450 continue;
451 for (i = 0; cont[i] != NULL; i++) {
452 assert(i < MAX_ENTRIES);
453 if (strcmp(cont[i], de->d_name) == 0) {
454 if (found[i]) {
455 ERROR("duplicate entry <%s>",
456 de->d_name);
457 err--;
458 } else
459 found[i] = 1;
460 break;
461 }
462 }
463 if (!cont[i]) {
464 ERROR("unexpected entry <%s>", de->d_name);
465 err --;
466 }
467 }
468 for (i = 0; cont[i] != NULL; i++) {
469 if (!found[i]) {
470 ERROR("missing entry <%s>", cont[i]);
471 err--;
472 }
473 }
474 res = closedir(dp);
475 if (res == -1) {
476 PERROR("closedir");
477 return -1;
478 }
479 if (err)
480 return -1;
481
482 return 0;
483}
484
485static int create_file(const char *path, const char *data, int len)
486{
487 int res;
488 int fd;
489
490 unlink(path);
491 fd = creat(path, 0644);
492 if (fd == -1) {
493 PERROR("creat");
494 return -1;
495 }
496 if (len) {
497 res = write(fd, data, len);
498 if (res == -1) {
499 PERROR("write");
500 close(fd);
501 return -1;
502 }
503 if (res != len) {
504 ERROR("write is short: %u instead of %u", res, len);
505 close(fd);
506 return -1;
507 }
508 }
509 res = close(fd);
510 if (res == -1) {
511 PERROR("close");
512 return -1;
513 }
514 res = check_type(path, S_IFREG);
515 if (res == -1)
516 return -1;
517 res = check_mode(path, 0644);
518 if (res == -1)
519 return -1;
520 res = check_nlink(path, 1);
521 if (res == -1)
522 return -1;
523 res = check_size(path, len);
524 if (res == -1)
525 return -1;
526
527 if (len) {
528 res = check_data(path, data, 0, len);
529 if (res == -1)
530 return -1;
531 }
532
533 return 0;
534}
535
536static int create_path_fd(const char *path, const char *data, int len)
537{
538 int path_fd;
539 int res;
540
541 res = create_file(path, data, len);
542 if (res == -1)
543 return -1;
544
545 path_fd = open(path, O_PATH);
546 if (path_fd == -1)
547 PERROR("open(O_PATH)");
548
549 return path_fd;
550}
551
552// Can be called once per test
553static int create_testfile(const char *path, const char *data, int len)
554{
555 struct test *t = this_test;
556 struct stat *st = &t->stat;
557 int res, fd;
558
559 if (t->fd > 0) {
560 ERROR("testfile already created");
561 return -1;
562 }
563
564 fd = create_path_fd(path, data, len);
565 if (fd == -1)
566 return -1;
567
568 t->fd = fd;
569
570 res = fstat(fd, st);
571 if (res == -1) {
572 PERROR("fstat");
573 return -1;
574 }
575
576 return 0;
577}
578
579static int check_unlinked_testfile(int fd)
580{
581 struct stat *st = &this_test->stat;
582
583 st->st_nlink = 0;
584 return fcheck_stat(fd, O_PATH, st);
585}
586
587// Check recorded testfiles after all tests completed
588static int check_unlinked_testfiles(void)
589{
590 int fd;
591 int res, err = 0;
592 int num = testnum;
593
594 if (!unlinked_test)
595 return 0;
596
597 testnum = 0;
598 while (testnum < num) {
599 fd = next_test->fd;
600 start_test("check_unlinked_testfile");
601 if (fd == -1)
602 continue;
603
604 err += check_unlinked_testfile(fd);
605 res = close(fd);
606 if (res == -1) {
607 PERROR("close(test_fd)");
608 err--;
609 }
610 }
611
612 if (err) {
613 fprintf(stderr, "%i unlinked testfile checks failed\n", -err);
614 return 1;
615 }
616
617 return err;
618}
619
620static int cleanup_dir(const char *path, const char **dir_files, int quiet)
621{
622 int i;
623 int err = 0;
624
625 for (i = 0; dir_files[i]; i++) {
626 int res;
627 char fpath[1280];
628 sprintf(fpath, "%s/%s", path, dir_files[i]);
629 res = unlink(fpath);
630 if (res == -1 && !quiet) {
631 PERROR("unlink");
632 err --;
633 }
634 }
635 if (err)
636 return -1;
637
638 return 0;
639}
640
641static int create_dir(const char *path, const char **dir_files)
642{
643 int res;
644 int i;
645
646 rmdir(path);
647 res = mkdir(path, 0755);
648 if (res == -1) {
649 PERROR("mkdir");
650 return -1;
651 }
652 res = check_type(path, S_IFDIR);
653 if (res == -1)
654 return -1;
655 res = check_mode(path, 0755);
656 if (res == -1)
657 return -1;
658
659 for (i = 0; dir_files[i]; i++) {
660 char fpath[1280];
661 sprintf(fpath, "%s/%s", path, dir_files[i]);
662 res = create_file(fpath, "", 0);
663 if (res == -1) {
664 cleanup_dir(path, dir_files, 1);
665 return -1;
666 }
667 }
668 res = check_dir_contents(path, dir_files);
669 if (res == -1) {
670 cleanup_dir(path, dir_files, 1);
671 return -1;
672 }
673
674 return 0;
675}
676
677static int test_truncate(int len)
678{
679 const char *data = testdata;
680 int datalen = testdatalen;
681 int res;
682
683 start_test("truncate(%u)", (int) len);
684 res = create_testfile(testfile, data, datalen);
685 if (res == -1)
686 return -1;
687
688 res = truncate(testfile, len);
689 if (res == -1) {
690 PERROR("truncate");
691 return -1;
692 }
693 res = check_testfile_size(testfile, len);
694 if (res == -1)
695 return -1;
696
697 if (len > 0) {
698 if (len <= datalen) {
699 res = check_data(testfile, data, 0, len);
700 if (res == -1)
701 return -1;
702 } else {
703 res = check_data(testfile, data, 0, datalen);
704 if (res == -1)
705 return -1;
706 res = check_data(testfile, zerodata, datalen,
707 len - datalen);
708 if (res == -1)
709 return -1;
710 }
711 }
712 res = unlink(testfile);
713 if (res == -1) {
714 PERROR("unlink");
715 return -1;
716 }
717 res = check_nonexist(testfile);
718 if (res == -1)
719 return -1;
720
721 success();
722 return 0;
723}
724
725static int test_ftruncate(int len, int mode)
726{
727 const char *data = testdata;
728 int datalen = testdatalen;
729 int res;
730 int fd;
731
732 start_test("ftruncate(%u) mode: 0%03o", len, mode);
733 res = create_testfile(testfile, data, datalen);
734 if (res == -1)
735 return -1;
736
737 fd = open(testfile, O_WRONLY);
738 if (fd == -1) {
739 PERROR("open");
740 return -1;
741 }
742
743 res = fchmod(fd, mode);
744 if (res == -1) {
745 PERROR("fchmod");
746 close(fd);
747 return -1;
748 }
749 res = check_testfile_mode(testfile, mode);
750 if (res == -1) {
751 close(fd);
752 return -1;
753 }
754 res = ftruncate(fd, len);
755 if (res == -1) {
756 PERROR("ftruncate");
757 close(fd);
758 return -1;
759 }
760 close(fd);
761 res = check_testfile_size(testfile, len);
762 if (res == -1)
763 return -1;
764
765 if (len > 0) {
766 if (len <= datalen) {
767 res = check_data(testfile, data, 0, len);
768 if (res == -1)
769 return -1;
770 } else {
771 res = check_data(testfile, data, 0, datalen);
772 if (res == -1)
773 return -1;
774 res = check_data(testfile, zerodata, datalen,
775 len - datalen);
776 if (res == -1)
777 return -1;
778 }
779 }
780 res = unlink(testfile);
781 if (res == -1) {
782 PERROR("unlink");
783 return -1;
784 }
785 res = check_nonexist(testfile);
786 if (res == -1)
787 return -1;
788
789 success();
790 return 0;
791}
792
793static int test_seekdir(void)
794{
795 int i;
796 int res;
797 DIR *dp;
798 struct dirent *de = NULL;
799
800 start_test("seekdir");
801 res = create_dir(testdir, testdir_files);
802 if (res == -1)
803 return res;
804
805 dp = opendir(testdir);
806 if (dp == NULL) {
807 PERROR("opendir");
808 return -1;
809 }
810
811 /* Remember dir offsets */
812 for (i = 0; i < ARRAY_SIZE(seekdir_offsets); i++) {
813 seekdir_offsets[i] = telldir(dp);
814 errno = 0;
815 de = readdir(dp);
816 if (de == NULL) {
817 if (errno) {
818 PERROR("readdir");
819 goto fail;
820 }
821 break;
822 }
823 }
824
825 /* Walk until the end of directory */
826 while (de)
827 de = readdir(dp);
828
829 /* Start from the last valid dir offset and seek backwards */
830 for (i--; i >= 0; i--) {
831 seekdir(dp, seekdir_offsets[i]);
832 de = readdir(dp);
833 if (de == NULL) {
834 ERROR("Unexpected end of directory after seekdir()");
835 goto fail;
836 }
837 }
838
839 closedir(dp);
840 res = cleanup_dir(testdir, testdir_files, 0);
841 if (!res)
842 success();
843 return res;
844fail:
845 closedir(dp);
846 cleanup_dir(testdir, testdir_files, 1);
847 return -1;
848}
849
850#ifdef HAVE_COPY_FILE_RANGE
851static int test_copy_file_range(void)
852{
853 const char *data = testdata;
854 int datalen = testdatalen;
855 int err = 0;
856 int res;
857 int fd_in, fd_out;
858 off_t pos_in = 0, pos_out = 0;
859
860 start_test("copy_file_range");
861 unlink(testfile);
862 fd_in = open(testfile, O_CREAT | O_RDWR, 0644);
863 if (fd_in == -1) {
864 PERROR("creat");
865 return -1;
866 }
867 res = write(fd_in, data, datalen);
868 if (res == -1) {
869 PERROR("write");
870 close(fd_in);
871 return -1;
872 }
873 if (res != datalen) {
874 ERROR("write is short: %u instead of %u", res, datalen);
875 close(fd_in);
876 return -1;
877 }
878
879 unlink(testfile2);
880 fd_out = creat(testfile2, 0644);
881 if (fd_out == -1) {
882 PERROR("creat");
883 close(fd_in);
884 return -1;
885 }
886 res = copy_file_range(fd_in, &pos_in, fd_out, &pos_out, datalen, 0);
887 if (res == -1) {
888 PERROR("copy_file_range");
889 close(fd_in);
890 close(fd_out);
891 return -1;
892 }
893 if (res != datalen) {
894 ERROR("copy is short: %u instead of %u", res, datalen);
895 close(fd_in);
896 close(fd_out);
897 return -1;
898 }
899
900 res = close(fd_in);
901 if (res == -1) {
902 PERROR("close");
903 close(fd_out);
904 return -1;
905 }
906 res = close(fd_out);
907 if (res == -1) {
908 PERROR("close");
909 return -1;
910 }
911
912 err = check_data(testfile2, data, 0, datalen);
913
914 res = unlink(testfile);
915 if (res == -1) {
916 PERROR("unlink");
917 return -1;
918 }
919 res = check_nonexist(testfile);
920 if (res == -1)
921 return -1;
922 if (err)
923 return -1;
924
925 res = unlink(testfile2);
926 if (res == -1) {
927 PERROR("unlink");
928 return -1;
929 }
930 res = check_nonexist(testfile2);
931 if (res == -1)
932 return -1;
933 if (err)
934 return -1;
935
936 success();
937 return 0;
938}
939#else
940static int test_copy_file_range(void)
941{
942 return 0;
943}
944#endif
945
946#ifdef HAVE_STATX
947static int test_statx(void)
948{
949 struct statx sb;
950 char msg[] = "hi";
951 size_t msg_size = sizeof(msg);
952 struct timespec tp;
953 int res;
954
955 memset(&sb, 0, sizeof(sb));
956 unlink(testfile);
957
958 start_test("statx");
959
960 res = create_testfile(testfile, msg, msg_size);
961 if (res == -1)
962 return -1;
963
964 res = statx(-1, testfile, AT_EMPTY_PATH,
965 STATX_BASIC_STATS | STATX_BTIME, &sb);
966 if (res == -1)
967 return -1;
968
969 if (sb.stx_size != msg_size)
970 return -1;
971
972 clock_gettime(CLOCK_REALTIME, &tp);
973
974 if (sb.stx_btime.tv_sec > tp.tv_sec)
975 return -1;
976
977 if (sb.stx_btime.tv_sec == tp.tv_sec &&
978 sb.stx_btime.tv_nsec >= tp.tv_nsec)
979 return -1;
980
981 unlink(testfile);
982
983 success();
984 return 0;
985}
986#else
987static int test_statx(void)
988{
989 return 0;
990}
991#endif
992
993static int test_utime(void)
994{
995 struct utimbuf utm;
996 time_t atime = 987631200;
997 time_t mtime = 123116400;
998 int res;
999
1000 start_test("utime");
1001 res = create_testfile(testfile, NULL, 0);
1002 if (res == -1)
1003 return -1;
1004
1005 utm.actime = atime;
1006 utm.modtime = mtime;
1007 res = utime(testfile, &utm);
1008 if (res == -1) {
1009 PERROR("utime");
1010 return -1;
1011 }
1012 res = check_times(testfile, atime, mtime);
1013 if (res == -1) {
1014 return -1;
1015 }
1016 res = unlink(testfile);
1017 if (res == -1) {
1018 PERROR("unlink");
1019 return -1;
1020 }
1021 res = check_nonexist(testfile);
1022 if (res == -1)
1023 return -1;
1024
1025 success();
1026 return 0;
1027}
1028
1029static int test_create(void)
1030{
1031 const char *data = testdata;
1032 int datalen = testdatalen;
1033 int err = 0;
1034 int res;
1035 int fd;
1036
1037 start_test("create");
1038 unlink(testfile);
1039 fd = creat(testfile, 0644);
1040 if (fd == -1) {
1041 PERROR("creat");
1042 return -1;
1043 }
1044 res = write(fd, data, datalen);
1045 if (res == -1) {
1046 PERROR("write");
1047 close(fd);
1048 return -1;
1049 }
1050 if (res != datalen) {
1051 ERROR("write is short: %u instead of %u", res, datalen);
1052 close(fd);
1053 return -1;
1054 }
1055 res = close(fd);
1056 if (res == -1) {
1057 PERROR("close");
1058 return -1;
1059 }
1060 res = check_type(testfile, S_IFREG);
1061 if (res == -1)
1062 return -1;
1063 err += check_mode(testfile, 0644);
1064 err += check_nlink(testfile, 1);
1065 err += check_size(testfile, datalen);
1066 err += check_data(testfile, data, 0, datalen);
1067 res = unlink(testfile);
1068 if (res == -1) {
1069 PERROR("unlink");
1070 return -1;
1071 }
1072 res = check_nonexist(testfile);
1073 if (res == -1)
1074 return -1;
1075 if (err)
1076 return -1;
1077
1078 success();
1079 return 0;
1080}
1081
1082static int test_create_unlink(void)
1083{
1084 const char *data = testdata;
1085 int datalen = testdatalen;
1086 int err = 0;
1087 int res;
1088 int fd;
1089
1090 start_test("create+unlink");
1091 unlink(testfile);
1092 fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644);
1093 if (fd == -1) {
1094 PERROR("creat");
1095 return -1;
1096 }
1097 res = unlink(testfile);
1098 if (res == -1) {
1099 PERROR("unlink");
1100 close(fd);
1101 return -1;
1102 }
1103 res = check_nonexist(testfile);
1104 if (res == -1) {
1105 close(fd);
1106 return -1;
1107 }
1108 res = write(fd, data, datalen);
1109 if (res == -1) {
1110 PERROR("write");
1111 close(fd);
1112 return -1;
1113 }
1114 if (res != datalen) {
1115 ERROR("write is short: %u instead of %u", res, datalen);
1116 close(fd);
1117 return -1;
1118 }
1119 struct stat st = {
1120 .st_mode = S_IFREG | 0644,
1121 .st_size = datalen,
1122 };
1123 err = fcheck_stat(fd, O_RDWR, &st);
1124 err += fcheck_data(fd, data, 0, datalen);
1125 res = close(fd);
1126 if (res == -1) {
1127 PERROR("close");
1128 err--;
1129 }
1130 if (err)
1131 return -1;
1132
1133 success();
1134 return 0;
1135}
1136
1137static int test_mknod(void)
1138{
1139 int err = 0;
1140 int res;
1141
1142 start_test("mknod");
1143 unlink(testfile);
1144 res = mknod(testfile, 0644, 0);
1145 if (res == -1) {
1146 PERROR("mknod");
1147 return -1;
1148 }
1149 res = check_type(testfile, S_IFREG);
1150 if (res == -1)
1151 return -1;
1152 err += check_mode(testfile, 0644);
1153 err += check_nlink(testfile, 1);
1154 err += check_size(testfile, 0);
1155 res = unlink(testfile);
1156 if (res == -1) {
1157 PERROR("unlink");
1158 return -1;
1159 }
1160 res = check_nonexist(testfile);
1161 if (res == -1)
1162 return -1;
1163 if (err)
1164 return -1;
1165
1166 success();
1167 return 0;
1168}
1169
1170#define test_open(exist, flags, mode) do_test_open(exist, flags, #flags, mode)
1171
1172static int do_test_open(int exist, int flags, const char *flags_str, int mode)
1173{
1174 char buf[4096];
1175 const char *data = testdata;
1176 int datalen = testdatalen;
1177 unsigned currlen = 0;
1178 int err = 0;
1179 int res;
1180 int fd;
1181 off_t off;
1182
1183 start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode);
1184 unlink(testfile);
1185 if (exist) {
1186 res = create_file(testfile_r, testdata2, testdata2len);
1187 if (res == -1)
1188 return -1;
1189
1190 currlen = testdata2len;
1191 }
1192
1193 fd = open(testfile, flags, mode);
1194 if ((flags & O_CREAT) && (flags & O_EXCL) && exist) {
1195 if (fd != -1) {
1196 ERROR("open should have failed");
1197 close(fd);
1198 return -1;
1199 } else if (errno == EEXIST)
1200 goto succ;
1201 }
1202 if (!(flags & O_CREAT) && !exist) {
1203 if (fd != -1) {
1204 ERROR("open should have failed");
1205 close(fd);
1206 return -1;
1207 } else if (errno == ENOENT)
1208 goto succ;
1209 }
1210 if (fd == -1) {
1211 PERROR("open");
1212 return -1;
1213 }
1214
1215 if (flags & O_TRUNC)
1216 currlen = 0;
1217
1218 err += check_type(testfile, S_IFREG);
1219 if (exist)
1220 err += check_mode(testfile, 0644);
1221 else
1222 err += check_mode(testfile, mode);
1223 err += check_nlink(testfile, 1);
1224 err += check_size(testfile, currlen);
1225 if (exist && !(flags & O_TRUNC) && (mode & S_IRUSR))
1226 err += check_data(testfile, testdata2, 0, testdata2len);
1227
1228 res = write(fd, data, datalen);
1229 if ((flags & O_ACCMODE) != O_RDONLY) {
1230 if (res == -1) {
1231 PERROR("write");
1232 err --;
1233 } else if (res != datalen) {
1234 ERROR("write is short: %u instead of %u", res, datalen);
1235 err --;
1236 } else {
1237 if (datalen > (int) currlen)
1238 currlen = datalen;
1239
1240 err += check_size(testfile, currlen);
1241
1242 if (mode & S_IRUSR) {
1243 err += check_data(testfile, data, 0, datalen);
1244 if (exist && !(flags & O_TRUNC) &&
1245 testdata2len > datalen)
1246 err += check_data(testfile,
1247 testdata2 + datalen,
1248 datalen,
1249 testdata2len - datalen);
1250 }
1251 }
1252 } else {
1253 if (res != -1) {
1254 ERROR("write should have failed");
1255 err --;
1256 } else if (errno != EBADF) {
1257 PERROR("write");
1258 err --;
1259 }
1260 }
1261 off = lseek(fd, SEEK_SET, 0);
1262 if (off == (off_t) -1) {
1263 PERROR("lseek");
1264 err--;
1265 } else if (off != 0) {
1266 ERROR("offset should have returned 0");
1267 err --;
1268 }
1269 res = read(fd, buf, sizeof(buf));
1270 if ((flags & O_ACCMODE) != O_WRONLY) {
1271 if (res == -1) {
1272 PERROR("read");
1273 err--;
1274 } else {
1275 int readsize =
1276 currlen < sizeof(buf) ? currlen : sizeof(buf);
1277 if (res != readsize) {
1278 ERROR("read is short: %i instead of %u",
1279 res, readsize);
1280 err--;
1281 } else {
1282 if ((flags & O_ACCMODE) != O_RDONLY) {
1283 err += check_buffer(buf, data, datalen);
1284 if (exist && !(flags & O_TRUNC) &&
1285 testdata2len > datalen)
1286 err += check_buffer(buf + datalen,
1287 testdata2 + datalen,
1288 testdata2len - datalen);
1289 } else if (exist)
1290 err += check_buffer(buf, testdata2,
1291 testdata2len);
1292 }
1293 }
1294 } else {
1295 if (res != -1) {
1296 ERROR("read should have failed");
1297 err --;
1298 } else if (errno != EBADF) {
1299 PERROR("read");
1300 err --;
1301 }
1302 }
1303
1304 res = close(fd);
1305 if (res == -1) {
1306 PERROR("close");
1307 return -1;
1308 }
1309 res = unlink(testfile);
1310 if (res == -1) {
1311 PERROR("unlink");
1312 return -1;
1313 }
1314 res = check_nonexist(testfile);
1315 if (res == -1)
1316 return -1;
1317 res = check_nonexist(testfile_r);
1318 if (res == -1)
1319 return -1;
1320 if (err)
1321 return -1;
1322
1323succ:
1324 success();
1325 return 0;
1326}
1327
1328#define test_open_acc(flags, mode, err) \
1329 do_test_open_acc(flags, #flags, mode, err)
1330
1331static int do_test_open_acc(int flags, const char *flags_str, int mode, int err)
1332{
1333 const char *data = testdata;
1334 int datalen = testdatalen;
1335 int res;
1336 int fd;
1337
1338 start_test("open_acc(%s) mode: 0%03o message: '%s'", flags_str, mode,
1339 strerror(err));
1340 unlink(testfile);
1341 res = create_testfile(testfile, data, datalen);
1342 if (res == -1)
1343 return -1;
1344
1345 res = chmod(testfile, mode);
1346 if (res == -1) {
1347 PERROR("chmod");
1348 return -1;
1349 }
1350
1351 res = check_testfile_mode(testfile, mode);
1352 if (res == -1)
1353 return -1;
1354
1355 fd = open(testfile, flags);
1356 if (fd == -1) {
1357 if (err != errno) {
1358 PERROR("open");
1359 return -1;
1360 }
1361 } else {
1362 if (err) {
1363 ERROR("open should have failed");
1364 close(fd);
1365 return -1;
1366 }
1367 close(fd);
1368 }
1369
1370 res = unlink(testfile);
1371 if (res == -1) {
1372 PERROR("unlink");
1373 return -1;
1374 }
1375 res = check_nonexist(testfile);
1376 if (res == -1)
1377 return -1;
1378 res = check_nonexist(testfile_r);
1379 if (res == -1)
1380 return -1;
1381
1382 success();
1383 return 0;
1384}
1385
1386static int test_symlink(void)
1387{
1388 char buf[1024];
1389 const char *data = testdata;
1390 int datalen = testdatalen;
1391 int linklen = strlen(testfile);
1392 int err = 0;
1393 int res;
1394
1395 start_test("symlink");
1396 res = create_testfile(testfile, data, datalen);
1397 if (res == -1)
1398 return -1;
1399
1400 unlink(testfile2);
1401 res = symlink(testfile, testfile2);
1402 if (res == -1) {
1403 PERROR("symlink");
1404 return -1;
1405 }
1406 res = check_type(testfile2, S_IFLNK);
1407 if (res == -1)
1408 return -1;
1409 err += check_mode(testfile2, 0777);
1410 err += check_nlink(testfile2, 1);
1411 res = readlink(testfile2, buf, sizeof(buf));
1412 if (res == -1) {
1413 PERROR("readlink");
1414 err--;
1415 }
1416 if (res != linklen) {
1417 ERROR("short readlink: %u instead of %u", res, linklen);
1418 err--;
1419 }
1420 if (memcmp(buf, testfile, linklen) != 0) {
1421 ERROR("link mismatch");
1422 err--;
1423 }
1424 err += check_size(testfile2, datalen);
1425 err += check_data(testfile2, data, 0, datalen);
1426 res = unlink(testfile2);
1427 if (res == -1) {
1428 PERROR("unlink");
1429 return -1;
1430 }
1431 res = check_nonexist(testfile2);
1432 if (res == -1)
1433 return -1;
1434 if (err)
1435 return -1;
1436
1437 res = unlink(testfile);
1438 if (res == -1) {
1439 PERROR("unlink");
1440 return -1;
1441 }
1442 res = check_nonexist(testfile);
1443 if (res == -1)
1444 return -1;
1445
1446 success();
1447 return 0;
1448}
1449
1450static int test_link(void)
1451{
1452 const char *data = testdata;
1453 int datalen = testdatalen;
1454 int err = 0;
1455 int res;
1456
1457 start_test("link");
1458 res = create_testfile(testfile, data, datalen);
1459 if (res == -1)
1460 return -1;
1461
1462 unlink(testfile2);
1463 res = link(testfile, testfile2);
1464 if (res == -1) {
1465 PERROR("link");
1466 return -1;
1467 }
1468 res = check_type(testfile2, S_IFREG);
1469 if (res == -1)
1470 return -1;
1471 err += check_mode(testfile2, 0644);
1472 err += check_nlink(testfile2, 2);
1473 err += check_size(testfile2, datalen);
1474 err += check_data(testfile2, data, 0, datalen);
1475 res = unlink(testfile);
1476 if (res == -1) {
1477 PERROR("unlink");
1478 return -1;
1479 }
1480 res = check_nonexist(testfile);
1481 if (res == -1)
1482 return -1;
1483
1484 err += check_nlink(testfile2, 1);
1485 res = unlink(testfile2);
1486 if (res == -1) {
1487 PERROR("unlink");
1488 return -1;
1489 }
1490 res = check_nonexist(testfile2);
1491 if (res == -1)
1492 return -1;
1493 if (err)
1494 return -1;
1495
1496 success();
1497 return 0;
1498}
1499
1500static int test_link2(void)
1501{
1502 const char *data = testdata;
1503 int datalen = testdatalen;
1504 int err = 0;
1505 int res;
1506
1507 start_test("link-unlink-link");
1508 res = create_testfile(testfile, data, datalen);
1509 if (res == -1)
1510 return -1;
1511
1512 unlink(testfile2);
1513 res = link(testfile, testfile2);
1514 if (res == -1) {
1515 PERROR("link");
1516 return -1;
1517 }
1518 res = unlink(testfile);
1519 if (res == -1) {
1520 PERROR("unlink");
1521 return -1;
1522 }
1523 res = check_nonexist(testfile);
1524 if (res == -1)
1525 return -1;
1526 res = link(testfile2, testfile);
1527 if (res == -1) {
1528 PERROR("link");
1529 }
1530 res = check_type(testfile, S_IFREG);
1531 if (res == -1)
1532 return -1;
1533 err += check_mode(testfile, 0644);
1534 err += check_nlink(testfile, 2);
1535 err += check_size(testfile, datalen);
1536 err += check_data(testfile, data, 0, datalen);
1537
1538 res = unlink(testfile2);
1539 if (res == -1) {
1540 PERROR("unlink");
1541 return -1;
1542 }
1543 err += check_nlink(testfile, 1);
1544 res = unlink(testfile);
1545 if (res == -1) {
1546 PERROR("unlink");
1547 return -1;
1548 }
1549 res = check_nonexist(testfile);
1550 if (res == -1)
1551 return -1;
1552 if (err)
1553 return -1;
1554
1555 success();
1556 return 0;
1557}
1558
1559static int test_rename_file(void)
1560{
1561 const char *data = testdata;
1562 int datalen = testdatalen;
1563 int err = 0;
1564 int res;
1565
1566 start_test("rename file");
1567 res = create_testfile(testfile, data, datalen);
1568 if (res == -1)
1569 return -1;
1570
1571 unlink(testfile2);
1572 res = rename(testfile, testfile2);
1573 if (res == -1) {
1574 PERROR("rename");
1575 return -1;
1576 }
1577 res = check_nonexist(testfile);
1578 if (res == -1)
1579 return -1;
1580 res = check_type(testfile2, S_IFREG);
1581 if (res == -1)
1582 return -1;
1583 err += check_mode(testfile2, 0644);
1584 err += check_nlink(testfile2, 1);
1585 err += check_size(testfile2, datalen);
1586 err += check_data(testfile2, data, 0, datalen);
1587 res = unlink(testfile2);
1588 if (res == -1) {
1589 PERROR("unlink");
1590 return -1;
1591 }
1592 res = check_nonexist(testfile2);
1593 if (res == -1)
1594 return -1;
1595 if (err)
1596 return -1;
1597
1598 success();
1599 return 0;
1600}
1601
1602static int test_rename_dir(void)
1603{
1604 int err = 0;
1605 int res;
1606
1607 start_test("rename dir");
1608 res = create_dir(testdir, testdir_files);
1609 if (res == -1)
1610 return -1;
1611
1612 rmdir(testdir2);
1613 res = rename(testdir, testdir2);
1614 if (res == -1) {
1615 PERROR("rename");
1616 cleanup_dir(testdir, testdir_files, 1);
1617 return -1;
1618 }
1619 res = check_nonexist(testdir);
1620 if (res == -1) {
1621 cleanup_dir(testdir, testdir_files, 1);
1622 return -1;
1623 }
1624 res = check_type(testdir2, S_IFDIR);
1625 if (res == -1) {
1626 cleanup_dir(testdir2, testdir_files, 1);
1627 return -1;
1628 }
1629 err += check_mode(testdir2, 0755);
1630 err += check_dir_contents(testdir2, testdir_files);
1631 err += cleanup_dir(testdir2, testdir_files, 0);
1632 res = rmdir(testdir2);
1633 if (res == -1) {
1634 PERROR("rmdir");
1635 return -1;
1636 }
1637 res = check_nonexist(testdir2);
1638 if (res == -1)
1639 return -1;
1640 if (err)
1641 return -1;
1642
1643 success();
1644 return 0;
1645}
1646
1647static int test_rename_dir_loop(void)
1648{
1649#define PATH(p) (snprintf(path, sizeof path, "%s/%s", testdir, p), path)
1650#define PATH2(p) (snprintf(path2, sizeof path2, "%s/%s", testdir, p), path2)
1651
1652 char path[1280], path2[1280];
1653 int err = 0;
1654 int res;
1655
1656 start_test("rename dir loop");
1657
1658 res = create_dir(testdir, testdir_files);
1659 if (res == -1)
1660 return -1;
1661
1662 res = mkdir(PATH("a"), 0755);
1663 if (res == -1) {
1664 PERROR("mkdir");
1665 goto fail;
1666 }
1667
1668 res = rename(PATH("a"), PATH2("a"));
1669 if (res == -1) {
1670 PERROR("rename");
1671 goto fail;
1672 }
1673
1674 errno = 0;
1675 res = rename(PATH("a"), PATH2("a/b"));
1676 if (res == 0 || errno != EINVAL) {
1677 PERROR("rename");
1678 goto fail;
1679 }
1680
1681 res = mkdir(PATH("a/b"), 0755);
1682 if (res == -1) {
1683 PERROR("mkdir");
1684 goto fail;
1685 }
1686
1687 res = mkdir(PATH("a/b/c"), 0755);
1688 if (res == -1) {
1689 PERROR("mkdir");
1690 goto fail;
1691 }
1692
1693 errno = 0;
1694 res = rename(PATH("a"), PATH2("a/b/c"));
1695 if (res == 0 || errno != EINVAL) {
1696 PERROR("rename");
1697 goto fail;
1698 }
1699
1700 errno = 0;
1701 res = rename(PATH("a"), PATH2("a/b/c/a"));
1702 if (res == 0 || errno != EINVAL) {
1703 PERROR("rename");
1704 goto fail;
1705 }
1706
1707 errno = 0;
1708 res = rename(PATH("a/b/c"), PATH2("a"));
1709 if (res == 0 || errno != ENOTEMPTY) {
1710 PERROR("rename");
1711 goto fail;
1712 }
1713
1714 res = open(PATH("a/foo"), O_CREAT, 0644);
1715 if (res == -1) {
1716 PERROR("open");
1717 goto fail;
1718 }
1719 close(res);
1720
1721 res = rename(PATH("a/foo"), PATH2("a/bar"));
1722 if (res == -1) {
1723 PERROR("rename");
1724 goto fail;
1725 }
1726
1727 res = rename(PATH("a/bar"), PATH2("a/foo"));
1728 if (res == -1) {
1729 PERROR("rename");
1730 goto fail;
1731 }
1732
1733 res = rename(PATH("a/foo"), PATH2("a/b/bar"));
1734 if (res == -1) {
1735 PERROR("rename");
1736 goto fail;
1737 }
1738
1739 res = rename(PATH("a/b/bar"), PATH2("a/foo"));
1740 if (res == -1) {
1741 PERROR("rename");
1742 goto fail;
1743 }
1744
1745 res = rename(PATH("a/foo"), PATH2("a/b/c/bar"));
1746 if (res == -1) {
1747 PERROR("rename");
1748 goto fail;
1749 }
1750
1751 res = rename(PATH("a/b/c/bar"), PATH2("a/foo"));
1752 if (res == -1) {
1753 PERROR("rename");
1754 goto fail;
1755 }
1756
1757 res = open(PATH("a/bar"), O_CREAT, 0644);
1758 if (res == -1) {
1759 PERROR("open");
1760 goto fail;
1761 }
1762 close(res);
1763
1764 res = rename(PATH("a/foo"), PATH2("a/bar"));
1765 if (res == -1) {
1766 PERROR("rename");
1767 goto fail;
1768 }
1769
1770 unlink(PATH("a/bar"));
1771
1772 res = rename(PATH("a/b"), PATH2("a/d"));
1773 if (res == -1) {
1774 PERROR("rename");
1775 goto fail;
1776 }
1777
1778 res = rename(PATH("a/d"), PATH2("a/b"));
1779 if (res == -1) {
1780 PERROR("rename");
1781 goto fail;
1782 }
1783
1784 res = mkdir(PATH("a/d"), 0755);
1785 if (res == -1) {
1786 PERROR("mkdir");
1787 goto fail;
1788 }
1789
1790 res = rename(PATH("a/b"), PATH2("a/d"));
1791 if (res == -1) {
1792 PERROR("rename");
1793 goto fail;
1794 }
1795
1796 res = rename(PATH("a/d"), PATH2("a/b"));
1797 if (res == -1) {
1798 PERROR("rename");
1799 goto fail;
1800 }
1801
1802 res = mkdir(PATH("a/d"), 0755);
1803 if (res == -1) {
1804 PERROR("mkdir");
1805 goto fail;
1806 }
1807
1808 res = mkdir(PATH("a/d/e"), 0755);
1809 if (res == -1) {
1810 PERROR("mkdir");
1811 goto fail;
1812 }
1813
1814 errno = 0;
1815 res = rename(PATH("a/b"), PATH2("a/d"));
1816 if (res == 0 || (errno != ENOTEMPTY && errno != EEXIST)) {
1817 PERROR("rename");
1818 goto fail;
1819 }
1820
1821 rmdir(PATH("a/d/e"));
1822 rmdir(PATH("a/d"));
1823
1824 rmdir(PATH("a/b/c"));
1825 rmdir(PATH("a/b"));
1826 rmdir(PATH("a"));
1827
1828 err += cleanup_dir(testdir, testdir_files, 0);
1829 res = rmdir(testdir);
1830 if (res == -1) {
1831 PERROR("rmdir");
1832 goto fail;
1833 }
1834 res = check_nonexist(testdir);
1835 if (res == -1)
1836 return -1;
1837 if (err)
1838 return -1;
1839
1840 success();
1841 return 0;
1842
1843fail:
1844 unlink(PATH("a/bar"));
1845
1846 rmdir(PATH("a/d/e"));
1847 rmdir(PATH("a/d"));
1848
1849 rmdir(PATH("a/b/c"));
1850 rmdir(PATH("a/b"));
1851 rmdir(PATH("a"));
1852
1853 cleanup_dir(testdir, testdir_files, 1);
1854 rmdir(testdir);
1855
1856 return -1;
1857
1858#undef PATH2
1859#undef PATH
1860}
1861
1862static int test_mkfifo(void)
1863{
1864 int res;
1865 int err = 0;
1866
1867 start_test("mkfifo");
1868 unlink(testfile);
1869 res = mkfifo(testfile, 0644);
1870 if (res == -1) {
1871 PERROR("mkfifo");
1872 return -1;
1873 }
1874 res = check_type(testfile, S_IFIFO);
1875 if (res == -1)
1876 return -1;
1877 err += check_mode(testfile, 0644);
1878 err += check_nlink(testfile, 1);
1879 res = unlink(testfile);
1880 if (res == -1) {
1881 PERROR("unlink");
1882 return -1;
1883 }
1884 res = check_nonexist(testfile);
1885 if (res == -1)
1886 return -1;
1887 if (err)
1888 return -1;
1889
1890 success();
1891 return 0;
1892}
1893
1894static int test_mkdir(void)
1895{
1896 int res;
1897 int err = 0;
1898 const char *dir_contents[] = {NULL};
1899
1900 start_test("mkdir");
1901 rmdir(testdir);
1902 res = mkdir(testdir, 0755);
1903 if (res == -1) {
1904 PERROR("mkdir");
1905 return -1;
1906 }
1907 res = check_type(testdir, S_IFDIR);
1908 if (res == -1)
1909 return -1;
1910 err += check_mode(testdir, 0755);
1911 /* Some file systems (like btrfs) don't track link
1912 count for directories */
1913 //err += check_nlink(testdir, 2);
1914 err += check_dir_contents(testdir, dir_contents);
1915 res = rmdir(testdir);
1916 if (res == -1) {
1917 PERROR("rmdir");
1918 return -1;
1919 }
1920 res = check_nonexist(testdir);
1921 if (res == -1)
1922 return -1;
1923 if (err)
1924 return -1;
1925
1926 success();
1927 return 0;
1928}
1929
1930static int test_socket(void)
1931{
1932 struct sockaddr_un su;
1933 int fd;
1934 int res;
1935 int err = 0;
1936 const size_t test_sock_len = strlen(testsock) + 1;
1937
1938 start_test("socket");
1939 if (test_sock_len > sizeof(su.sun_path)) {
1940 fprintf(stderr, "Need to shorten mount point by %zu chars\n",
1941 strlen(testsock) + 1 - sizeof(su.sun_path));
1942 return -1;
1943 }
1944 unlink(testsock);
1945 fd = socket(AF_UNIX, SOCK_STREAM, 0);
1946 if (fd < 0) {
1947 PERROR("socket");
1948 return -1;
1949 }
1950 su.sun_family = AF_UNIX;
1951
1952 strncpy(su.sun_path, testsock, test_sock_len);
1953 su.sun_path[sizeof(su.sun_path) - 1] = '\0';
1954 res = bind(fd, (struct sockaddr*)&su, sizeof(su));
1955 if (res == -1) {
1956 PERROR("bind");
1957 return -1;
1958 }
1959
1960 res = check_type(testsock, S_IFSOCK);
1961 if (res == -1) {
1962 close(fd);
1963 return -1;
1964 }
1965 err += check_nlink(testsock, 1);
1966 close(fd);
1967 res = unlink(testsock);
1968 if (res == -1) {
1969 PERROR("unlink");
1970 return -1;
1971 }
1972 res = check_nonexist(testsock);
1973 if (res == -1)
1974 return -1;
1975 if (err)
1976 return -1;
1977
1978 success();
1979 return 0;
1980}
1981
1982#define test_create_ro_dir(flags) \
1983 do_test_create_ro_dir(flags, #flags)
1984
1985static int do_test_create_ro_dir(int flags, const char *flags_str)
1986{
1987 int res;
1988 int err = 0;
1989 int fd;
1990
1991 start_test("open(%s) in read-only directory", flags_str);
1992 rmdir(testdir);
1993 res = mkdir(testdir, 0555);
1994 if (res == -1) {
1995 PERROR("mkdir");
1996 return -1;
1997 }
1998 fd = open(subfile, flags, 0644);
1999 if (fd != -1) {
2000 close(fd);
2001 unlink(subfile);
2002 ERROR("open should have failed");
2003 err--;
2004 } else {
2005 res = check_nonexist(subfile);
2006 if (res == -1)
2007 err--;
2008 }
2009 unlink(subfile);
2010 res = rmdir(testdir);
2011 if (res == -1) {
2012 PERROR("rmdir");
2013 return -1;
2014 }
2015 res = check_nonexist(testdir);
2016 if (res == -1)
2017 return -1;
2018 if (err)
2019 return -1;
2020
2021 success();
2022 return 0;
2023}
2024
2025#ifndef __FreeBSD__
2026/* this tests open with O_TMPFILE
2027 note that this will only work with the fuse low level api
2028 you will get ENOTSUP with the high level api */
2029static int test_create_tmpfile(void)
2030{
2031 rmdir(testdir);
2032 int res = mkdir(testdir, 0777);
2033 if (res)
2034 return -1;
2035
2036 start_test("create tmpfile");
2037
2038 int fd = open(testdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
2039 if(fd == -1) {
2040 if (errno == ENOTSUP) {
2041 /* don't bother if we're working on an old kernel
2042 or on the high level API */
2043 return 0;
2044 }
2045
2046 PERROR("open O_TMPFILE | O_RDWR");
2047 return -1;
2048 }
2049 close(fd);
2050
2051 fd = open(testdir, O_TMPFILE | O_WRONLY | O_EXCL, S_IRUSR | S_IWUSR);
2052 if(fd == -1){
2053 PERROR("open with O_TMPFILE | O_WRONLY | O_EXCL");
2054 return -1;
2055 };
2056 close(fd);
2057
2058 fd = open(testdir, O_TMPFILE | O_RDONLY, S_IRUSR);
2059 if (fd != -1) {
2060 ERROR("open with O_TMPFILE | O_RDONLY succeeded");
2061 return -1;
2062 }
2063
2064 success();
2065 return 0;
2066}
2067
2068static int test_create_and_link_tmpfile(void)
2069{
2070 /* skip this test for now since the github runner will fail in the linkat call below */
2071 return 0;
2072
2073 rmdir(testdir);
2074 unlink(testfile);
2075
2076 int res = mkdir(testdir, 0777);
2077 if (res)
2078 return -1;
2079
2080 start_test("create and link tmpfile");
2081
2082 int fd = open(testdir, O_TMPFILE | O_RDWR | O_EXCL, S_IRUSR | S_IWUSR);
2083 if(fd == -1) {
2084 if (errno == ENOTSUP) {
2085 /* don't bother if we're working on an old kernel
2086 or on the high level API */
2087 return 0;
2088 }
2089 PERROR("open with O_TMPFILE | O_RDWR | O_EXCL");
2090 return -1;
2091 }
2092
2093 if (!linkat(fd, "", AT_FDCWD, testfile, AT_EMPTY_PATH)) {
2094 ERROR("linkat succeeded on a tmpfile opened with O_EXCL");
2095 return -1;
2096 }
2097 close(fd);
2098
2099 fd = open(testdir, O_TMPFILE | O_RDWR, S_IRUSR | S_IWUSR);
2100 if(fd == -1) {
2101 PERROR("open O_TMPFILE");
2102 return -1;
2103 }
2104
2105 if (check_nonexist(testfile)) {
2106 return -1;
2107 }
2108
2109 if (linkat(fd, "", AT_FDCWD, testfile, AT_EMPTY_PATH)) {
2110 PERROR("linkat tempfile");
2111 return -1;
2112 }
2113 close(fd);
2114
2115 if (check_nlink(testfile, 1)) {
2116 return -1;
2117 }
2118 unlink(testfile);
2119
2120 success();
2121 return 0;
2122}
2123#endif
2124
2125int main(int argc, char *argv[])
2126{
2127 int err = 0;
2128 int a;
2129 int is_root;
2130
2131 /* Piped stdout is fully buffered, so a killed test loses whatever it
2132 * had printed about what it was doing.
2133 */
2134 setvbuf(stdout, NULL, _IOLBF, 0);
2135
2136 umask(0);
2137 if (argc < 2 || argc > 4) {
2138 fprintf(stderr, "usage: %s testdir [:realdir] [[-]test#] [-u]\n", argv[0]);
2139 return 1;
2140 }
2141 basepath = argv[1];
2142 basepath_r = basepath;
2143 for (a = 2; a < argc; a++) {
2144 char *endptr;
2145 char *arg = argv[a];
2146 if (arg[0] == ':') {
2147 basepath_r = arg + 1;
2148 } else {
2149 if (arg[0] == '-') {
2150 arg++;
2151 if (arg[0] == 'u') {
2152 unlinked_test = 1;
2153 endptr = arg + 1;
2154 } else {
2155 skip_test = strtoul(arg, &endptr, 10);
2156 }
2157 } else {
2158 select_test = strtoul(arg, &endptr, 10);
2159 }
2160 if (arg[0] == '\0' || *endptr != '\0') {
2161 fprintf(stderr, "invalid option: '%s'\n", argv[a]);
2162 return 1;
2163 }
2164 }
2165 }
2166 assert(strlen(basepath) < 512);
2167 assert(strlen(basepath_r) < 512);
2168 if (basepath[0] != '/') {
2169 fprintf(stderr, "testdir must be an absolute path\n");
2170 return 1;
2171 }
2172
2173 sprintf(testfile, "%s/testfile", basepath);
2174 sprintf(testfile2, "%s/testfile2", basepath);
2175 sprintf(testdir, "%s/testdir", basepath);
2176 sprintf(testdir2, "%s/testdir2", basepath);
2177 sprintf(subfile, "%s/subfile", testdir2);
2178 sprintf(testsock, "%s/testsock", basepath);
2179
2180 sprintf(testfile_r, "%s/testfile", basepath_r);
2181 sprintf(testfile2_r, "%s/testfile2", basepath_r);
2182 sprintf(testdir_r, "%s/testdir", basepath_r);
2183 sprintf(testdir2_r, "%s/testdir2", basepath_r);
2184 sprintf(subfile_r, "%s/subfile", testdir2_r);
2185
2186 is_root = (geteuid() == 0);
2187
2188 err += test_create();
2189 err += test_create_unlink();
2190 err += test_symlink();
2191 err += test_link();
2192 err += test_link2();
2193 err += test_mknod();
2194 err += test_mkfifo();
2195 err += test_mkdir();
2196 err += test_rename_file();
2197 err += test_rename_dir();
2198 err += test_rename_dir_loop();
2199 err += test_seekdir();
2200 err += test_socket();
2201 err += test_utime();
2202 err += test_truncate(0);
2203 err += test_truncate(testdatalen / 2);
2204 err += test_truncate(testdatalen);
2205 err += test_truncate(testdatalen + 100);
2206 err += test_ftruncate(0, 0600);
2207 err += test_ftruncate(testdatalen / 2, 0600);
2208 err += test_ftruncate(testdatalen, 0600);
2209 err += test_ftruncate(testdatalen + 100, 0600);
2210 err += test_ftruncate(0, 0400);
2211 err += test_ftruncate(0, 0200);
2212 err += test_ftruncate(0, 0000);
2213 err += test_open(0, O_RDONLY, 0);
2214 err += test_open(1, O_RDONLY, 0);
2215 err += test_open(1, O_RDWR, 0);
2216 err += test_open(1, O_WRONLY, 0);
2217 err += test_open(0, O_RDWR | O_CREAT, 0600);
2218 err += test_open(1, O_RDWR | O_CREAT, 0600);
2219 err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600);
2220 err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600);
2221 err += test_open(0, O_RDONLY | O_CREAT, 0600);
2222 err += test_open(0, O_RDONLY | O_CREAT, 0400);
2223 err += test_open(0, O_RDONLY | O_CREAT, 0200);
2224 err += test_open(0, O_RDONLY | O_CREAT, 0000);
2225 err += test_open(0, O_WRONLY | O_CREAT, 0600);
2226 err += test_open(0, O_WRONLY | O_CREAT, 0400);
2227 err += test_open(0, O_WRONLY | O_CREAT, 0200);
2228 err += test_open(0, O_WRONLY | O_CREAT, 0000);
2229 err += test_open(0, O_RDWR | O_CREAT, 0400);
2230 err += test_open(0, O_RDWR | O_CREAT, 0200);
2231 err += test_open(0, O_RDWR | O_CREAT, 0000);
2232 err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600);
2233 err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600);
2234 err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000);
2235 err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000);
2236 err += test_open_acc(O_RDONLY, 0600, 0);
2237 err += test_open_acc(O_WRONLY, 0600, 0);
2238 err += test_open_acc(O_RDWR, 0600, 0);
2239 err += test_open_acc(O_RDONLY, 0400, 0);
2240 err += test_open_acc(O_WRONLY, 0200, 0);
2241 if(!is_root) {
2242 err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES);
2243 err += test_open_acc(O_WRONLY, 0400, EACCES);
2244 err += test_open_acc(O_RDWR, 0400, EACCES);
2245 err += test_open_acc(O_RDONLY, 0200, EACCES);
2246 err += test_open_acc(O_RDWR, 0200, EACCES);
2247 err += test_open_acc(O_RDONLY, 0000, EACCES);
2248 err += test_open_acc(O_WRONLY, 0000, EACCES);
2249 err += test_open_acc(O_RDWR, 0000, EACCES);
2250 }
2251 err += test_create_ro_dir(O_CREAT);
2252 err += test_create_ro_dir(O_CREAT | O_EXCL);
2253 err += test_create_ro_dir(O_CREAT | O_WRONLY);
2254 err += test_create_ro_dir(O_CREAT | O_TRUNC);
2255 err += test_copy_file_range();
2256 err += test_statx();
2257#ifndef __FreeBSD__
2258 err += test_create_tmpfile();
2259 err += test_create_and_link_tmpfile();
2260#endif
2261
2262 unlink(testfile2);
2263 unlink(testsock);
2264 rmdir(testdir);
2265 rmdir(testdir2);
2266
2267 if (err) {
2268 fprintf(stderr, "%i tests failed\n", -err);
2269 return 1;
2270 }
2271
2272 return check_unlinked_testfiles();
2273}