libfuse
test_syscalls.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <string.h>
5 #include <unistd.h>
6 #include <fcntl.h>
7 #include <dirent.h>
8 #include <utime.h>
9 #include <errno.h>
10 #include <assert.h>
11 #include <sys/types.h>
12 #include <sys/stat.h>
13 
14 
15 static char testfile[1024];
16 static char testfile2[1024];
17 static char testdir[1024];
18 static char testdir2[1024];
19 static char subfile[1024];
20 
21 static char testfile_r[1024];
22 static char testfile2_r[1024];
23 static char testdir_r[1024];
24 static char testdir2_r[1024];
25 static char subfile_r[1024];
26 
27 static char testname[256];
28 static char testdata[] = "abcdefghijklmnopqrstuvwxyz";
29 static char testdata2[] = "1234567890-=qwertyuiop[]\asdfghjkl;'zxcvbnm,./";
30 static const char *testdir_files[] = { "f1", "f2", NULL};
31 static char zerodata[4096];
32 static int testdatalen = sizeof(testdata) - 1;
33 static int testdata2len = sizeof(testdata2) - 1;
34 static unsigned int testnum = 1;
35 static unsigned int select_test = 0;
36 static unsigned int skip_test = 0;
37 
38 #define MAX_ENTRIES 1024
39 
40 static void test_perror(const char *func, const char *msg)
41 {
42  fprintf(stderr, "%s %s() - %s: %s\n", testname, func, msg,
43  strerror(errno));
44 }
45 
46 static void test_error(const char *func, const char *msg, ...)
47  __attribute__ ((format (printf, 2, 3)));
48 
49 static void __start_test(const char *fmt, ...)
50  __attribute__ ((format (printf, 1, 2)));
51 
52 static void test_error(const char *func, const char *msg, ...)
53 {
54  va_list ap;
55  fprintf(stderr, "%s %s() - ", testname, func);
56  va_start(ap, msg);
57  vfprintf(stderr, msg, ap);
58  va_end(ap);
59  fprintf(stderr, "\n");
60 }
61 
62 static void success(void)
63 {
64  fprintf(stderr, "%s OK\n", testname);
65 }
66 
67 static void __start_test(const char *fmt, ...)
68 {
69  unsigned int n;
70  va_list ap;
71  n = sprintf(testname, "%3i [", testnum++);
72  va_start(ap, fmt);
73  n += vsprintf(testname + n, fmt, ap);
74  va_end(ap);
75  sprintf(testname + n, "]");
76 }
77 
78 #define start_test(msg, args...) { \
79  if ((select_test && testnum != select_test) || \
80  (testnum == skip_test)) { \
81  testnum++; \
82  return 0; \
83  } \
84  __start_test(msg, ##args); \
85 }
86 
87 #define PERROR(msg) test_perror(__FUNCTION__, msg)
88 #define ERROR(msg, args...) test_error(__FUNCTION__, msg, ##args)
89 
90 static int check_size(const char *path, int len)
91 {
92  struct stat stbuf;
93  int res = stat(path, &stbuf);
94  if (res == -1) {
95  PERROR("stat");
96  return -1;
97  }
98  if (stbuf.st_size != len) {
99  ERROR("length %u instead of %u", (int) stbuf.st_size,
100  (int) len);
101  return -1;
102  }
103  return 0;
104 }
105 
106 static int fcheck_size(int fd, int len)
107 {
108  struct stat stbuf;
109  int res = fstat(fd, &stbuf);
110  if (res == -1) {
111  PERROR("fstat");
112  return -1;
113  }
114  if (stbuf.st_size != len) {
115  ERROR("length %u instead of %u", (int) stbuf.st_size,
116  (int) len);
117  return -1;
118  }
119  return 0;
120 }
121 
122 static int check_type(const char *path, mode_t type)
123 {
124  struct stat stbuf;
125  int res = lstat(path, &stbuf);
126  if (res == -1) {
127  PERROR("lstat");
128  return -1;
129  }
130  if ((stbuf.st_mode & S_IFMT) != type) {
131  ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type);
132  return -1;
133  }
134  return 0;
135 }
136 
137 static int fcheck_type(int fd, mode_t type)
138 {
139  struct stat stbuf;
140  int res = fstat(fd, &stbuf);
141  if (res == -1) {
142  PERROR("fstat");
143  return -1;
144  }
145  if ((stbuf.st_mode & S_IFMT) != type) {
146  ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type);
147  return -1;
148  }
149  return 0;
150 }
151 
152 static int check_mode(const char *path, mode_t mode)
153 {
154  struct stat stbuf;
155  int res = lstat(path, &stbuf);
156  if (res == -1) {
157  PERROR("lstat");
158  return -1;
159  }
160  if ((stbuf.st_mode & 07777) != mode) {
161  ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode);
162  return -1;
163  }
164  return 0;
165 }
166 
167 static int fcheck_mode(int fd, mode_t mode)
168 {
169  struct stat stbuf;
170  int res = fstat(fd, &stbuf);
171  if (res == -1) {
172  PERROR("fstat");
173  return -1;
174  }
175  if ((stbuf.st_mode & 07777) != mode) {
176  ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode);
177  return -1;
178  }
179  return 0;
180 }
181 
182 static int check_times(const char *path, time_t atime, time_t mtime)
183 {
184  int err = 0;
185  struct stat stbuf;
186  int res = lstat(path, &stbuf);
187  if (res == -1) {
188  PERROR("lstat");
189  return -1;
190  }
191  if (stbuf.st_atime != atime) {
192  ERROR("atime %li instead of %li", stbuf.st_atime, atime);
193  err--;
194  }
195  if (stbuf.st_mtime != mtime) {
196  ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime);
197  err--;
198  }
199  if (err)
200  return -1;
201 
202  return 0;
203 }
204 
205 #if 0
206 static int fcheck_times(int fd, time_t atime, time_t mtime)
207 {
208  int err = 0;
209  struct stat stbuf;
210  int res = fstat(fd, &stbuf);
211  if (res == -1) {
212  PERROR("fstat");
213  return -1;
214  }
215  if (stbuf.st_atime != atime) {
216  ERROR("atime %li instead of %li", stbuf.st_atime, atime);
217  err--;
218  }
219  if (stbuf.st_mtime != mtime) {
220  ERROR("mtime %li instead of %li", stbuf.st_mtime, mtime);
221  err--;
222  }
223  if (err)
224  return -1;
225 
226  return 0;
227 }
228 #endif
229 
230 static int check_nlink(const char *path, nlink_t nlink)
231 {
232  struct stat stbuf;
233  int res = lstat(path, &stbuf);
234  if (res == -1) {
235  PERROR("lstat");
236  return -1;
237  }
238  if (stbuf.st_nlink != nlink) {
239  ERROR("nlink %li instead of %li", (long) stbuf.st_nlink,
240  (long) nlink);
241  return -1;
242  }
243  return 0;
244 }
245 
246 static int fcheck_nlink(int fd, nlink_t nlink)
247 {
248  struct stat stbuf;
249  int res = fstat(fd, &stbuf);
250  if (res == -1) {
251  PERROR("fstat");
252  return -1;
253  }
254  if (stbuf.st_nlink != nlink) {
255  ERROR("nlink %li instead of %li", (long) stbuf.st_nlink,
256  (long) nlink);
257  return -1;
258  }
259  return 0;
260 }
261 
262 static int check_nonexist(const char *path)
263 {
264  struct stat stbuf;
265  int res = lstat(path, &stbuf);
266  if (res == 0) {
267  ERROR("file should not exist");
268  return -1;
269  }
270  if (errno != ENOENT) {
271  ERROR("file should not exist: %s", strerror(errno));
272  return -1;
273  }
274  return 0;
275 }
276 
277 static int check_buffer(const char *buf, const char *data, unsigned len)
278 {
279  if (memcmp(buf, data, len) != 0) {
280  ERROR("data mismatch");
281  return -1;
282  }
283  return 0;
284 }
285 
286 static int check_data(const char *path, const char *data, int offset,
287  unsigned len)
288 {
289  char buf[4096];
290  int res;
291  int fd = open(path, O_RDONLY);
292  if (fd == -1) {
293  PERROR("open");
294  return -1;
295  }
296  if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
297  PERROR("lseek");
298  close(fd);
299  return -1;
300  }
301  while (len) {
302  int rdlen = len < sizeof(buf) ? len : sizeof(buf);
303  res = read(fd, buf, rdlen);
304  if (res == -1) {
305  PERROR("read");
306  close(fd);
307  return -1;
308  }
309  if (res != rdlen) {
310  ERROR("short read: %u instead of %u", res, rdlen);
311  close(fd);
312  return -1;
313  }
314  if (check_buffer(buf, data, rdlen) != 0) {
315  close(fd);
316  return -1;
317  }
318  data += rdlen;
319  len -= rdlen;
320  }
321  res = close(fd);
322  if (res == -1) {
323  PERROR("close");
324  return -1;
325  }
326  return 0;
327 }
328 
329 static int fcheck_data(int fd, const char *data, int offset,
330  unsigned len)
331 {
332  char buf[4096];
333  int res;
334  if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
335  PERROR("lseek");
336  return -1;
337  }
338  while (len) {
339  int rdlen = len < sizeof(buf) ? len : sizeof(buf);
340  res = read(fd, buf, rdlen);
341  if (res == -1) {
342  PERROR("read");
343  return -1;
344  }
345  if (res != rdlen) {
346  ERROR("short read: %u instead of %u", res, rdlen);
347  return -1;
348  }
349  if (check_buffer(buf, data, rdlen) != 0) {
350  return -1;
351  }
352  data += rdlen;
353  len -= rdlen;
354  }
355  return 0;
356 }
357 
358 static int check_dir_contents(const char *path, const char **contents)
359 {
360  int i;
361  int res;
362  int err = 0;
363  int found[MAX_ENTRIES];
364  const char *cont[MAX_ENTRIES];
365  DIR *dp;
366 
367  for (i = 0; contents[i]; i++) {
368  assert(i < MAX_ENTRIES - 3);
369  found[i] = 0;
370  cont[i] = contents[i];
371  }
372  found[i] = 0;
373  cont[i++] = ".";
374  found[i] = 0;
375  cont[i++] = "..";
376  cont[i] = NULL;
377 
378  dp = opendir(path);
379  if (dp == NULL) {
380  PERROR("opendir");
381  return -1;
382  }
383  memset(found, 0, sizeof(found));
384  while(1) {
385  struct dirent *de;
386  errno = 0;
387  de = readdir(dp);
388  if (de == NULL) {
389  if (errno) {
390  PERROR("readdir");
391  closedir(dp);
392  return -1;
393  }
394  break;
395  }
396  for (i = 0; cont[i] != NULL; i++) {
397  assert(i < MAX_ENTRIES);
398  if (strcmp(cont[i], de->d_name) == 0) {
399  if (found[i]) {
400  ERROR("duplicate entry <%s>",
401  de->d_name);
402  err--;
403  } else
404  found[i] = 1;
405  break;
406  }
407  }
408  if (!cont[i]) {
409  ERROR("unexpected entry <%s>", de->d_name);
410  err --;
411  }
412  }
413  for (i = 0; cont[i] != NULL; i++) {
414  if (!found[i]) {
415  ERROR("missing entry <%s>", cont[i]);
416  err--;
417  }
418  }
419  res = closedir(dp);
420  if (res == -1) {
421  PERROR("closedir");
422  return -1;
423  }
424  if (err)
425  return -1;
426 
427  return 0;
428 }
429 
430 static int create_file(const char *path, const char *data, int len)
431 {
432  int res;
433  int fd;
434 
435  unlink(path);
436  fd = creat(path, 0644);
437  if (fd == -1) {
438  PERROR("creat");
439  return -1;
440  }
441  if (len) {
442  res = write(fd, data, len);
443  if (res == -1) {
444  PERROR("write");
445  close(fd);
446  return -1;
447  }
448  if (res != len) {
449  ERROR("write is short: %u instead of %u", res, len);
450  close(fd);
451  return -1;
452  }
453  }
454  res = close(fd);
455  if (res == -1) {
456  PERROR("close");
457  return -1;
458  }
459  res = check_type(path, S_IFREG);
460  if (res == -1)
461  return -1;
462  res = check_mode(path, 0644);
463  if (res == -1)
464  return -1;
465  res = check_nlink(path, 1);
466  if (res == -1)
467  return -1;
468  res = check_size(path, len);
469  if (res == -1)
470  return -1;
471 
472  if (len) {
473  res = check_data(path, data, 0, len);
474  if (res == -1)
475  return -1;
476  }
477 
478  return 0;
479 }
480 
481 static int cleanup_dir(const char *path, const char **dir_files, int quiet)
482 {
483  int i;
484  int err = 0;
485 
486  for (i = 0; dir_files[i]; i++) {
487  int res;
488  char fpath[1024];
489  sprintf(fpath, "%s/%s", path, dir_files[i]);
490  res = unlink(fpath);
491  if (res == -1 && !quiet) {
492  PERROR("unlink");
493  err --;
494  }
495  }
496  if (err)
497  return -1;
498 
499  return 0;
500 }
501 
502 static int create_dir(const char *path, const char **dir_files)
503 {
504  int res;
505  int i;
506 
507  rmdir(path);
508  res = mkdir(path, 0755);
509  if (res == -1) {
510  PERROR("mkdir");
511  return -1;
512  }
513  res = check_type(path, S_IFDIR);
514  if (res == -1)
515  return -1;
516  res = check_mode(path, 0755);
517  if (res == -1)
518  return -1;
519 
520  for (i = 0; dir_files[i]; i++) {
521  char fpath[1024];
522  sprintf(fpath, "%s/%s", path, dir_files[i]);
523  res = create_file(fpath, "", 0);
524  if (res == -1) {
525  cleanup_dir(path, dir_files, 1);
526  return -1;
527  }
528  }
529  res = check_dir_contents(path, dir_files);
530  if (res == -1) {
531  cleanup_dir(path, dir_files, 1);
532  return -1;
533  }
534 
535  return 0;
536 }
537 
538 static int test_truncate(int len)
539 {
540  const char *data = testdata;
541  int datalen = testdatalen;
542  int res;
543 
544  start_test("truncate(%u)", (int) len);
545  res = create_file(testfile, data, datalen);
546  if (res == -1)
547  return -1;
548 
549  res = truncate(testfile, len);
550  if (res == -1) {
551  PERROR("truncate");
552  return -1;
553  }
554  res = check_size(testfile, len);
555  if (res == -1)
556  return -1;
557 
558  if (len > 0) {
559  if (len <= datalen) {
560  res = check_data(testfile, data, 0, len);
561  if (res == -1)
562  return -1;
563  } else {
564  res = check_data(testfile, data, 0, datalen);
565  if (res == -1)
566  return -1;
567  res = check_data(testfile, zerodata, datalen,
568  len - datalen);
569  if (res == -1)
570  return -1;
571  }
572  }
573  res = unlink(testfile);
574  if (res == -1) {
575  PERROR("unlink");
576  return -1;
577  }
578  res = check_nonexist(testfile);
579  if (res == -1)
580  return -1;
581 
582  success();
583  return 0;
584 }
585 
586 static int test_ftruncate(int len, int mode)
587 {
588  const char *data = testdata;
589  int datalen = testdatalen;
590  int res;
591  int fd;
592 
593  start_test("ftruncate(%u) mode: 0%03o", len, mode);
594  res = create_file(testfile, data, datalen);
595  if (res == -1)
596  return -1;
597 
598  fd = open(testfile, O_WRONLY);
599  if (fd == -1) {
600  PERROR("open");
601  return -1;
602  }
603 
604  res = fchmod(fd, mode);
605  if (res == -1) {
606  PERROR("fchmod");
607  close(fd);
608  return -1;
609  }
610  res = check_mode(testfile, mode);
611  if (res == -1) {
612  close(fd);
613  return -1;
614  }
615  res = ftruncate(fd, len);
616  if (res == -1) {
617  PERROR("ftruncate");
618  close(fd);
619  return -1;
620  }
621  close(fd);
622  res = check_size(testfile, len);
623  if (res == -1)
624  return -1;
625 
626  if (len > 0) {
627  if (len <= datalen) {
628  res = check_data(testfile, data, 0, len);
629  if (res == -1)
630  return -1;
631  } else {
632  res = check_data(testfile, data, 0, datalen);
633  if (res == -1)
634  return -1;
635  res = check_data(testfile, zerodata, datalen,
636  len - datalen);
637  if (res == -1)
638  return -1;
639  }
640  }
641  res = unlink(testfile);
642  if (res == -1) {
643  PERROR("unlink");
644  return -1;
645  }
646  res = check_nonexist(testfile);
647  if (res == -1)
648  return -1;
649 
650  success();
651  return 0;
652 }
653 
654 static int test_utime(void)
655 {
656  struct utimbuf utm;
657  time_t atime = 987631200;
658  time_t mtime = 123116400;
659  int res;
660 
661  start_test("utime");
662  res = create_file(testfile, NULL, 0);
663  if (res == -1)
664  return -1;
665 
666  utm.actime = atime;
667  utm.modtime = mtime;
668  res = utime(testfile, &utm);
669  if (res == -1) {
670  PERROR("utime");
671  return -1;
672  }
673  res = check_times(testfile, atime, mtime);
674  if (res == -1) {
675  return -1;
676  }
677  res = unlink(testfile);
678  if (res == -1) {
679  PERROR("unlink");
680  return -1;
681  }
682  res = check_nonexist(testfile);
683  if (res == -1)
684  return -1;
685 
686  success();
687  return 0;
688 }
689 
690 static int test_create(void)
691 {
692  const char *data = testdata;
693  int datalen = testdatalen;
694  int err = 0;
695  int res;
696  int fd;
697 
698  start_test("create");
699  unlink(testfile);
700  fd = creat(testfile, 0644);
701  if (fd == -1) {
702  PERROR("creat");
703  return -1;
704  }
705  res = write(fd, data, datalen);
706  if (res == -1) {
707  PERROR("write");
708  close(fd);
709  return -1;
710  }
711  if (res != datalen) {
712  ERROR("write is short: %u instead of %u", res, datalen);
713  close(fd);
714  return -1;
715  }
716  res = close(fd);
717  if (res == -1) {
718  PERROR("close");
719  return -1;
720  }
721  res = check_type(testfile, S_IFREG);
722  if (res == -1)
723  return -1;
724  err += check_mode(testfile, 0644);
725  err += check_nlink(testfile, 1);
726  err += check_size(testfile, datalen);
727  err += check_data(testfile, data, 0, datalen);
728  res = unlink(testfile);
729  if (res == -1) {
730  PERROR("unlink");
731  return -1;
732  }
733  res = check_nonexist(testfile);
734  if (res == -1)
735  return -1;
736  if (err)
737  return -1;
738 
739  success();
740  return 0;
741 }
742 
743 static int test_create_unlink(void)
744 {
745  const char *data = testdata;
746  int datalen = testdatalen;
747  int err = 0;
748  int res;
749  int fd;
750 
751  start_test("create+unlink");
752  unlink(testfile);
753  fd = open(testfile, O_CREAT | O_RDWR | O_TRUNC, 0644);
754  if (fd == -1) {
755  PERROR("creat");
756  return -1;
757  }
758  res = unlink(testfile);
759  if (res == -1) {
760  PERROR("unlink");
761  close(fd);
762  return -1;
763  }
764  res = check_nonexist(testfile);
765  if (res == -1)
766  return -1;
767  res = write(fd, data, datalen);
768  if (res == -1) {
769  PERROR("write");
770  close(fd);
771  return -1;
772  }
773  if (res != datalen) {
774  ERROR("write is short: %u instead of %u", res, datalen);
775  close(fd);
776  return -1;
777  }
778  err += fcheck_type(fd, S_IFREG);
779  err += fcheck_mode(fd, 0644);
780  err += fcheck_nlink(fd, 0);
781  err += fcheck_size(fd, datalen);
782  err += fcheck_data(fd, data, 0, datalen);
783  res = close(fd);
784  if (res == -1) {
785  PERROR("close");
786  err--;
787  }
788  if (err)
789  return -1;
790 
791  success();
792  return 0;
793 }
794 
795 #ifndef __FreeBSD__
796 static int test_mknod(void)
797 {
798  int err = 0;
799  int res;
800 
801  start_test("mknod");
802  unlink(testfile);
803  res = mknod(testfile, 0644, 0);
804  if (res == -1) {
805  PERROR("mknod");
806  return -1;
807  }
808  res = check_type(testfile, S_IFREG);
809  if (res == -1)
810  return -1;
811  err += check_mode(testfile, 0644);
812  err += check_nlink(testfile, 1);
813  err += check_size(testfile, 0);
814  res = unlink(testfile);
815  if (res == -1) {
816  PERROR("unlink");
817  return -1;
818  }
819  res = check_nonexist(testfile);
820  if (res == -1)
821  return -1;
822  if (err)
823  return -1;
824 
825  success();
826  return 0;
827 }
828 #endif
829 
830 #define test_open(exist, flags, mode) do_test_open(exist, flags, #flags, mode)
831 
832 static int do_test_open(int exist, int flags, const char *flags_str, int mode)
833 {
834  char buf[4096];
835  const char *data = testdata;
836  int datalen = testdatalen;
837  unsigned currlen = 0;
838  int err = 0;
839  int res;
840  int fd;
841  off_t off;
842 
843  start_test("open(%s, %s, 0%03o)", exist ? "+" : "-", flags_str, mode);
844  unlink(testfile);
845  if (exist) {
846  res = create_file(testfile_r, testdata2, testdata2len);
847  if (res == -1)
848  return -1;
849 
850  currlen = testdata2len;
851  }
852 
853  fd = open(testfile, flags, mode);
854  if ((flags & O_CREAT) && (flags & O_EXCL) && exist) {
855  if (fd != -1) {
856  ERROR("open should have failed");
857  close(fd);
858  return -1;
859  } else if (errno == EEXIST)
860  goto succ;
861  }
862  if (!(flags & O_CREAT) && !exist) {
863  if (fd != -1) {
864  ERROR("open should have failed");
865  close(fd);
866  return -1;
867  } else if (errno == ENOENT)
868  goto succ;
869  }
870  if (fd == -1) {
871  PERROR("open");
872  return -1;
873  }
874 
875  if (flags & O_TRUNC)
876  currlen = 0;
877 
878  err += check_type(testfile, S_IFREG);
879  if (exist)
880  err += check_mode(testfile, 0644);
881  else
882  err += check_mode(testfile, mode);
883  err += check_nlink(testfile, 1);
884  err += check_size(testfile, currlen);
885  if (exist && !(flags & O_TRUNC) && (mode & 0400))
886  err += check_data(testfile, testdata2, 0, testdata2len);
887 
888  res = write(fd, data, datalen);
889  if ((flags & O_ACCMODE) != O_RDONLY) {
890  if (res == -1) {
891  PERROR("write");
892  err --;
893  } else if (res != datalen) {
894  ERROR("write is short: %u instead of %u", res, datalen);
895  err --;
896  } else {
897  if (datalen > (int) currlen)
898  currlen = datalen;
899 
900  err += check_size(testfile, currlen);
901 
902  if (mode & 0400) {
903  err += check_data(testfile, data, 0, datalen);
904  if (exist && !(flags & O_TRUNC) &&
905  testdata2len > datalen)
906  err += check_data(testfile,
907  testdata2 + datalen,
908  datalen,
909  testdata2len - datalen);
910  }
911  }
912  } else {
913  if (res != -1) {
914  ERROR("write should have failed");
915  err --;
916  } else if (errno != EBADF) {
917  PERROR("write");
918  err --;
919  }
920  }
921  off = lseek(fd, SEEK_SET, 0);
922  if (off == (off_t) -1) {
923  PERROR("lseek");
924  err--;
925  } else if (off != 0) {
926  ERROR("offset should have returned 0");
927  err --;
928  }
929  res = read(fd, buf, sizeof(buf));
930  if ((flags & O_ACCMODE) != O_WRONLY) {
931  if (res == -1) {
932  PERROR("read");
933  err--;
934  } else {
935  int readsize =
936  currlen < sizeof(buf) ? currlen : sizeof(buf);
937  if (res != readsize) {
938  ERROR("read is short: %i instead of %u",
939  res, readsize);
940  err--;
941  } else {
942  if ((flags & O_ACCMODE) != O_RDONLY) {
943  err += check_buffer(buf, data, datalen);
944  if (exist && !(flags & O_TRUNC) &&
945  testdata2len > datalen)
946  err += check_buffer(buf + datalen,
947  testdata2 + datalen,
948  testdata2len - datalen);
949  } else if (exist)
950  err += check_buffer(buf, testdata2,
951  testdata2len);
952  }
953  }
954  } else {
955  if (res != -1) {
956  ERROR("read should have failed");
957  err --;
958  } else if (errno != EBADF) {
959  PERROR("read");
960  err --;
961  }
962  }
963 
964  res = close(fd);
965  if (res == -1) {
966  PERROR("close");
967  return -1;
968  }
969  res = unlink(testfile);
970  if (res == -1) {
971  PERROR("unlink");
972  return -1;
973  }
974  res = check_nonexist(testfile);
975  if (res == -1)
976  return -1;
977  res = check_nonexist(testfile_r);
978  if (res == -1)
979  return -1;
980  if (err)
981  return -1;
982 
983 succ:
984  success();
985  return 0;
986 }
987 
988 #define test_open_acc(flags, mode, err) \
989  do_test_open_acc(flags, #flags, mode, err)
990 
991 static int do_test_open_acc(int flags, const char *flags_str, int mode, int err)
992 {
993  const char *data = testdata;
994  int datalen = testdatalen;
995  int res;
996  int fd;
997 
998  start_test("open_acc(%s) mode: 0%03o message: '%s'", flags_str, mode,
999  strerror(err));
1000  unlink(testfile);
1001  res = create_file(testfile, data, datalen);
1002  if (res == -1)
1003  return -1;
1004 
1005  res = chmod(testfile, mode);
1006  if (res == -1) {
1007  PERROR("chmod");
1008  return -1;
1009  }
1010 
1011  res = check_mode(testfile, mode);
1012  if (res == -1)
1013  return -1;
1014 
1015  fd = open(testfile, flags);
1016  if (fd == -1) {
1017  if (err != errno) {
1018  PERROR("open");
1019  return -1;
1020  }
1021  } else {
1022  if (err) {
1023  ERROR("open should have failed");
1024  close(fd);
1025  return -1;
1026  }
1027  close(fd);
1028  }
1029  success();
1030  return 0;
1031 }
1032 
1033 static int test_symlink(void)
1034 {
1035  char buf[1024];
1036  const char *data = testdata;
1037  int datalen = testdatalen;
1038  int linklen = strlen(testfile);
1039  int err = 0;
1040  int res;
1041 
1042  start_test("symlink");
1043  res = create_file(testfile, data, datalen);
1044  if (res == -1)
1045  return -1;
1046 
1047  unlink(testfile2);
1048  res = symlink(testfile, testfile2);
1049  if (res == -1) {
1050  PERROR("symlink");
1051  return -1;
1052  }
1053  res = check_type(testfile2, S_IFLNK);
1054  if (res == -1)
1055  return -1;
1056  err += check_mode(testfile2, 0777);
1057  err += check_nlink(testfile2, 1);
1058  res = readlink(testfile2, buf, sizeof(buf));
1059  if (res == -1) {
1060  PERROR("readlink");
1061  err--;
1062  }
1063  if (res != linklen) {
1064  ERROR("short readlink: %u instead of %u", res, linklen);
1065  err--;
1066  }
1067  if (memcmp(buf, testfile, linklen) != 0) {
1068  ERROR("link mismatch");
1069  err--;
1070  }
1071  err += check_size(testfile2, datalen);
1072  err += check_data(testfile2, data, 0, datalen);
1073  res = unlink(testfile2);
1074  if (res == -1) {
1075  PERROR("unlink");
1076  return -1;
1077  }
1078  res = check_nonexist(testfile2);
1079  if (res == -1)
1080  return -1;
1081  if (err)
1082  return -1;
1083 
1084  success();
1085  return 0;
1086 }
1087 
1088 static int test_link(void)
1089 {
1090  const char *data = testdata;
1091  int datalen = testdatalen;
1092  int err = 0;
1093  int res;
1094 
1095  start_test("link");
1096  res = create_file(testfile, data, datalen);
1097  if (res == -1)
1098  return -1;
1099 
1100  unlink(testfile2);
1101  res = link(testfile, testfile2);
1102  if (res == -1) {
1103  PERROR("link");
1104  return -1;
1105  }
1106  res = check_type(testfile2, S_IFREG);
1107  if (res == -1)
1108  return -1;
1109  err += check_mode(testfile2, 0644);
1110  err += check_nlink(testfile2, 2);
1111  err += check_size(testfile2, datalen);
1112  err += check_data(testfile2, data, 0, datalen);
1113  res = unlink(testfile);
1114  if (res == -1) {
1115  PERROR("unlink");
1116  return -1;
1117  }
1118  res = check_nonexist(testfile);
1119  if (res == -1)
1120  return -1;
1121 
1122  err += check_nlink(testfile2, 1);
1123  res = unlink(testfile2);
1124  if (res == -1) {
1125  PERROR("unlink");
1126  return -1;
1127  }
1128  res = check_nonexist(testfile2);
1129  if (res == -1)
1130  return -1;
1131  if (err)
1132  return -1;
1133 
1134  success();
1135  return 0;
1136 }
1137 
1138 static int test_link2(void)
1139 {
1140  const char *data = testdata;
1141  int datalen = testdatalen;
1142  int err = 0;
1143  int res;
1144 
1145  start_test("link-unlink-link");
1146  res = create_file(testfile, data, datalen);
1147  if (res == -1)
1148  return -1;
1149 
1150  unlink(testfile2);
1151  res = link(testfile, testfile2);
1152  if (res == -1) {
1153  PERROR("link");
1154  return -1;
1155  }
1156  res = unlink(testfile);
1157  if (res == -1) {
1158  PERROR("unlink");
1159  return -1;
1160  }
1161  res = check_nonexist(testfile);
1162  if (res == -1)
1163  return -1;
1164  res = link(testfile2, testfile);
1165  if (res == -1) {
1166  PERROR("link");
1167  }
1168  res = check_type(testfile, S_IFREG);
1169  if (res == -1)
1170  return -1;
1171  err += check_mode(testfile, 0644);
1172  err += check_nlink(testfile, 2);
1173  err += check_size(testfile, datalen);
1174  err += check_data(testfile, data, 0, datalen);
1175 
1176  res = unlink(testfile2);
1177  if (res == -1) {
1178  PERROR("unlink");
1179  return -1;
1180  }
1181  err += check_nlink(testfile, 1);
1182  res = unlink(testfile);
1183  if (res == -1) {
1184  PERROR("unlink");
1185  return -1;
1186  }
1187  res = check_nonexist(testfile);
1188  if (res == -1)
1189  return -1;
1190  if (err)
1191  return -1;
1192 
1193  success();
1194  return 0;
1195 }
1196 
1197 static int test_rename_file(void)
1198 {
1199  const char *data = testdata;
1200  int datalen = testdatalen;
1201  int err = 0;
1202  int res;
1203 
1204  start_test("rename file");
1205  res = create_file(testfile, data, datalen);
1206  if (res == -1)
1207  return -1;
1208 
1209  unlink(testfile2);
1210  res = rename(testfile, testfile2);
1211  if (res == -1) {
1212  PERROR("rename");
1213  return -1;
1214  }
1215  res = check_nonexist(testfile);
1216  if (res == -1)
1217  return -1;
1218  res = check_type(testfile2, S_IFREG);
1219  if (res == -1)
1220  return -1;
1221  err += check_mode(testfile2, 0644);
1222  err += check_nlink(testfile2, 1);
1223  err += check_size(testfile2, datalen);
1224  err += check_data(testfile2, data, 0, datalen);
1225  res = unlink(testfile2);
1226  if (res == -1) {
1227  PERROR("unlink");
1228  return -1;
1229  }
1230  res = check_nonexist(testfile2);
1231  if (res == -1)
1232  return -1;
1233  if (err)
1234  return -1;
1235 
1236  success();
1237  return 0;
1238 }
1239 
1240 static int test_rename_dir(void)
1241 {
1242  int err = 0;
1243  int res;
1244 
1245  start_test("rename dir");
1246  res = create_dir(testdir, testdir_files);
1247  if (res == -1)
1248  return -1;
1249 
1250  rmdir(testdir2);
1251  res = rename(testdir, testdir2);
1252  if (res == -1) {
1253  PERROR("rename");
1254  cleanup_dir(testdir, testdir_files, 1);
1255  return -1;
1256  }
1257  res = check_nonexist(testdir);
1258  if (res == -1) {
1259  cleanup_dir(testdir, testdir_files, 1);
1260  return -1;
1261  }
1262  res = check_type(testdir2, S_IFDIR);
1263  if (res == -1) {
1264  cleanup_dir(testdir2, testdir_files, 1);
1265  return -1;
1266  }
1267  err += check_mode(testdir2, 0755);
1268  err += check_dir_contents(testdir2, testdir_files);
1269  err += cleanup_dir(testdir2, testdir_files, 0);
1270  res = rmdir(testdir2);
1271  if (res == -1) {
1272  PERROR("rmdir");
1273  return -1;
1274  }
1275  res = check_nonexist(testdir2);
1276  if (res == -1)
1277  return -1;
1278  if (err)
1279  return -1;
1280 
1281  success();
1282  return 0;
1283 }
1284 
1285 #ifndef __FreeBSD__
1286 static int test_mkfifo(void)
1287 {
1288  int res;
1289  int err = 0;
1290 
1291  start_test("mkfifo");
1292  unlink(testfile);
1293  res = mkfifo(testfile, 0644);
1294  if (res == -1) {
1295  PERROR("mkfifo");
1296  return -1;
1297  }
1298  res = check_type(testfile, S_IFIFO);
1299  if (res == -1)
1300  return -1;
1301  err += check_mode(testfile, 0644);
1302  err += check_nlink(testfile, 1);
1303  res = unlink(testfile);
1304  if (res == -1) {
1305  PERROR("unlink");
1306  return -1;
1307  }
1308  res = check_nonexist(testfile);
1309  if (res == -1)
1310  return -1;
1311  if (err)
1312  return -1;
1313 
1314  success();
1315  return 0;
1316 }
1317 #endif
1318 
1319 static int test_mkdir(void)
1320 {
1321  int res;
1322  int err = 0;
1323  const char *dir_contents[] = {NULL};
1324 
1325  start_test("mkdir");
1326  rmdir(testdir);
1327  res = mkdir(testdir, 0755);
1328  if (res == -1) {
1329  PERROR("mkdir");
1330  return -1;
1331  }
1332  res = check_type(testdir, S_IFDIR);
1333  if (res == -1)
1334  return -1;
1335  err += check_mode(testdir, 0755);
1336  /* Some file systems (like btrfs) don't track link
1337  count for directories */
1338  //err += check_nlink(testdir, 2);
1339  err += check_dir_contents(testdir, dir_contents);
1340  res = rmdir(testdir);
1341  if (res == -1) {
1342  PERROR("rmdir");
1343  return -1;
1344  }
1345  res = check_nonexist(testdir);
1346  if (res == -1)
1347  return -1;
1348  if (err)
1349  return -1;
1350 
1351  success();
1352  return 0;
1353 }
1354 
1355 #define test_create_ro_dir(flags) \
1356  do_test_create_ro_dir(flags, #flags)
1357 
1358 static int do_test_create_ro_dir(int flags, const char *flags_str)
1359 {
1360  int res;
1361  int err = 0;
1362  int fd;
1363 
1364  start_test("open(%s) in read-only directory", flags_str);
1365  rmdir(testdir);
1366  res = mkdir(testdir, 0555);
1367  if (res == -1) {
1368  PERROR("mkdir");
1369  return -1;
1370  }
1371  fd = open(subfile, flags, 0644);
1372  if (fd != -1) {
1373  close(fd);
1374  unlink(subfile);
1375  ERROR("open should have failed");
1376  err--;
1377  } else {
1378  res = check_nonexist(subfile);
1379  if (res == -1)
1380  err--;
1381  }
1382  unlink(subfile);
1383  res = rmdir(testdir);
1384  if (res == -1) {
1385  PERROR("rmdir");
1386  return -1;
1387  }
1388  res = check_nonexist(testdir);
1389  if (res == -1)
1390  return -1;
1391  if (err)
1392  return -1;
1393 
1394  success();
1395  return 0;
1396 }
1397 
1398 int main(int argc, char *argv[])
1399 {
1400  const char *basepath;
1401  const char *realpath;
1402  int err = 0;
1403  int a;
1404  int is_root;
1405 
1406  umask(0);
1407  if (argc < 2 || argc > 4) {
1408  fprintf(stderr, "usage: %s testdir [:realdir] [[-]test#]\n", argv[0]);
1409  return 1;
1410  }
1411  basepath = argv[1];
1412  realpath = basepath;
1413  for (a = 2; a < argc; a++) {
1414  char *endptr;
1415  char *arg = argv[a];
1416  if (arg[0] == ':') {
1417  realpath = arg + 1;
1418  } else {
1419  if (arg[0] == '-') {
1420  arg++;
1421  skip_test = strtoul(arg, &endptr, 10);
1422  } else {
1423  select_test = strtoul(arg, &endptr, 10);
1424  }
1425  if (arg[0] == '\0' || *endptr != '\0') {
1426  fprintf(stderr, "invalid number: '%s'\n", arg);
1427  return 1;
1428  }
1429  }
1430  }
1431  assert(strlen(basepath) < 512);
1432  assert(strlen(realpath) < 512);
1433  if (basepath[0] != '/') {
1434  fprintf(stderr, "testdir must be an absolute path\n");
1435  return 1;
1436  }
1437 
1438  sprintf(testfile, "%s/testfile", basepath);
1439  sprintf(testfile2, "%s/testfile2", basepath);
1440  sprintf(testdir, "%s/testdir", basepath);
1441  sprintf(testdir2, "%s/testdir2", basepath);
1442  sprintf(subfile, "%s/subfile", testdir2);
1443 
1444  sprintf(testfile_r, "%s/testfile", realpath);
1445  sprintf(testfile2_r, "%s/testfile2", realpath);
1446  sprintf(testdir_r, "%s/testdir", realpath);
1447  sprintf(testdir2_r, "%s/testdir2", realpath);
1448  sprintf(subfile_r, "%s/subfile", testdir2_r);
1449 
1450  is_root = (geteuid() == 0);
1451 
1452  err += test_create();
1453  err += test_create_unlink();
1454  err += test_symlink();
1455  err += test_link();
1456  err += test_link2();
1457 #ifndef __FreeBSD__
1458  err += test_mknod();
1459  err += test_mkfifo();
1460 #endif
1461  err += test_mkdir();
1462  err += test_rename_file();
1463  err += test_rename_dir();
1464  err += test_utime();
1465  err += test_truncate(0);
1466  err += test_truncate(testdatalen / 2);
1467  err += test_truncate(testdatalen);
1468  err += test_truncate(testdatalen + 100);
1469  err += test_ftruncate(0, 0600);
1470  err += test_ftruncate(testdatalen / 2, 0600);
1471  err += test_ftruncate(testdatalen, 0600);
1472  err += test_ftruncate(testdatalen + 100, 0600);
1473  err += test_ftruncate(0, 0400);
1474  err += test_ftruncate(0, 0200);
1475  err += test_ftruncate(0, 0000);
1476  err += test_open(0, O_RDONLY, 0);
1477  err += test_open(1, O_RDONLY, 0);
1478  err += test_open(1, O_RDWR, 0);
1479  err += test_open(1, O_WRONLY, 0);
1480  err += test_open(0, O_RDWR | O_CREAT, 0600);
1481  err += test_open(1, O_RDWR | O_CREAT, 0600);
1482  err += test_open(0, O_RDWR | O_CREAT | O_TRUNC, 0600);
1483  err += test_open(1, O_RDWR | O_CREAT | O_TRUNC, 0600);
1484  err += test_open(0, O_RDONLY | O_CREAT, 0600);
1485  err += test_open(0, O_RDONLY | O_CREAT, 0400);
1486  err += test_open(0, O_RDONLY | O_CREAT, 0200);
1487  err += test_open(0, O_RDONLY | O_CREAT, 0000);
1488  err += test_open(0, O_WRONLY | O_CREAT, 0600);
1489  err += test_open(0, O_WRONLY | O_CREAT, 0400);
1490  err += test_open(0, O_WRONLY | O_CREAT, 0200);
1491  err += test_open(0, O_WRONLY | O_CREAT, 0000);
1492  err += test_open(0, O_RDWR | O_CREAT, 0400);
1493  err += test_open(0, O_RDWR | O_CREAT, 0200);
1494  err += test_open(0, O_RDWR | O_CREAT, 0000);
1495  err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0600);
1496  err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0600);
1497  err += test_open(0, O_RDWR | O_CREAT | O_EXCL, 0000);
1498  err += test_open(1, O_RDWR | O_CREAT | O_EXCL, 0000);
1499  err += test_open_acc(O_RDONLY, 0600, 0);
1500  err += test_open_acc(O_WRONLY, 0600, 0);
1501  err += test_open_acc(O_RDWR, 0600, 0);
1502  err += test_open_acc(O_RDONLY, 0400, 0);
1503  err += test_open_acc(O_WRONLY, 0200, 0);
1504  if(!is_root) {
1505  err += test_open_acc(O_RDONLY | O_TRUNC, 0400, EACCES);
1506  err += test_open_acc(O_WRONLY, 0400, EACCES);
1507  err += test_open_acc(O_RDWR, 0400, EACCES);
1508  err += test_open_acc(O_RDONLY, 0200, EACCES);
1509  err += test_open_acc(O_RDWR, 0200, EACCES);
1510  err += test_open_acc(O_RDONLY, 0000, EACCES);
1511  err += test_open_acc(O_WRONLY, 0000, EACCES);
1512  err += test_open_acc(O_RDWR, 0000, EACCES);
1513  }
1514  err += test_create_ro_dir(O_CREAT);
1515  err += test_create_ro_dir(O_CREAT | O_EXCL);
1516  err += test_create_ro_dir(O_CREAT | O_WRONLY);
1517  err += test_create_ro_dir(O_CREAT | O_TRUNC);
1518 
1519  unlink(testfile);
1520  unlink(testfile2);
1521  rmdir(testdir);
1522  rmdir(testdir2);
1523 
1524  if (err) {
1525  fprintf(stderr, "%i tests failed\n", -err);
1526  return 1;
1527  }
1528 
1529  return 0;
1530 }