blob: dfc9feaeb533501fdba6e7d530440a74e2606b15 [file] [log] [blame]
Miklos Szeredi3b206c72005-05-06 10:15:26 +00001#include <stdio.h>
2#include <stdarg.h>
3#include <string.h>
4#include <unistd.h>
5#include <fcntl.h>
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +00006#include <dirent.h>
Miklos Szeredi3b206c72005-05-06 10:15:26 +00007#include <errno.h>
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +00008#include <assert.h>
Miklos Szeredi3b206c72005-05-06 10:15:26 +00009#include <sys/types.h>
10#include <sys/stat.h>
11
12
13static char testfile[1024];
14static char testfile2[1024];
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +000015static char testdir[1024];
16static char testdir2[1024];
Miklos Szeredi3b206c72005-05-06 10:15:26 +000017static char testname[256];
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +000018static char testdata[] = "abcdefghijklmnopqrstuvwxyz";
19static const char *testdir_files[] = { "f1", "f2", NULL};
Miklos Szeredi3b206c72005-05-06 10:15:26 +000020static char zerodata[4096];
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +000021static int testdatalen = sizeof(testdata) - 1;
22
23#define MAX_ENTRIES 1024
Miklos Szeredi3b206c72005-05-06 10:15:26 +000024
25static void test_perror(const char *func, const char *msg)
26{
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +000027 fprintf(stderr, "[%s] %s() - %s: %s\n", testname, func, msg,
28 strerror(errno));
Miklos Szeredi3b206c72005-05-06 10:15:26 +000029}
30
31static void test_error(const char *func, const char *msg, ...)
32 __attribute__ ((format (printf, 2, 3)));
33
34static void start_test(const char *fmt, ...)
35 __attribute__ ((format (printf, 1, 2)));
Miklos Szeredi9b813af2005-07-21 07:59:37 +000036
Miklos Szeredi3b206c72005-05-06 10:15:26 +000037static void test_error(const char *func, const char *msg, ...)
38{
39 va_list ap;
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +000040 fprintf(stderr, "[%s] %s() - ", testname, func);
Miklos Szeredi3b206c72005-05-06 10:15:26 +000041 va_start(ap, msg);
42 vfprintf(stderr, msg, ap);
43 va_end(ap);
44 fprintf(stderr, "\n");
45}
46
47static void success(void)
48{
49 fprintf(stderr, "[%s] OK\n", testname);
50}
51
52static void start_test(const char *fmt, ...)
53{
54 va_list ap;
55 va_start(ap, fmt);
56 vsprintf(testname, fmt, ap);
57 va_end(ap);
58}
59
60#define PERROR(msg) test_perror(__FUNCTION__, msg)
61#define ERROR(msg, args...) test_error(__FUNCTION__, msg, ##args)
62
63static int check_size(const char *path, int len)
64{
65 struct stat stbuf;
66 int res = stat(path, &stbuf);
67 if (res == -1) {
68 PERROR("stat");
69 return -1;
70 }
71 if (stbuf.st_size != len) {
72 ERROR("length %u instead of %u", (int) stbuf.st_size, (int) len);
73 return -1;
74 }
75 return 0;
76}
77
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +000078static int check_type(const char *path, mode_t type)
79{
80 struct stat stbuf;
81 int res = lstat(path, &stbuf);
82 if (res == -1) {
83 PERROR("lstat");
84 return -1;
85 }
86 if ((stbuf.st_mode & S_IFMT) != type) {
87 ERROR("type 0%o instead of 0%o", stbuf.st_mode & S_IFMT, type);
88 return -1;
89 }
90 return 0;
91}
92
93static int check_mode(const char *path, mode_t mode)
94{
95 struct stat stbuf;
96 int res = lstat(path, &stbuf);
97 if (res == -1) {
98 PERROR("lstat");
99 return -1;
100 }
101 if ((stbuf.st_mode & 07777) != mode) {
102 ERROR("mode 0%o instead of 0%o", stbuf.st_mode & 07777, mode);
103 return -1;
104 }
105 return 0;
106}
107
108static int check_nlink(const char *path, nlink_t nlink)
109{
110 struct stat stbuf;
111 int res = lstat(path, &stbuf);
112 if (res == -1) {
113 PERROR("lstat");
114 return -1;
115 }
116 if (stbuf.st_nlink != nlink) {
117 ERROR("nlink %i instead of %i", stbuf.st_nlink, nlink);
118 return -1;
119 }
120 return 0;
121}
122
123static int check_nonexist(const char *path)
124{
125 struct stat stbuf;
126 int res = lstat(path, &stbuf);
127 if (res == 0) {
128 ERROR("file should not exist");
129 return -1;
130 }
131 if (errno != ENOENT) {
132 ERROR("file should not exist: %s", strerror(errno));
133 return -1;
134 }
135 return 0;
136}
137
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000138static int check_data(const char *path, const char *data, int offset,
139 unsigned len)
140{
141 char buf[4096];
142 int res;
143 int fd = open(path, O_RDONLY);
144 if (fd == -1) {
145 PERROR("open");
146 return -1;
147 }
148 if (lseek(fd, offset, SEEK_SET) == (off_t) -1) {
149 PERROR("lseek");
150 close(fd);
151 return -1;
152 }
153 while (len) {
154 int rdlen = len < sizeof(buf) ? len : sizeof(buf);
155 res = read(fd, buf, rdlen);
156 if (res == -1) {
157 PERROR("read");
158 close(fd);
159 return -1;
160 }
161 if (res != rdlen) {
162 ERROR("short read: %u instead of %u", res, rdlen);
163 close(fd);
164 return -1;
165 }
166 if (memcmp(buf, data, rdlen) != 0) {
167 ERROR("data mismatch");
168 close(fd);
169 return -1;
170 }
171 data += rdlen;
172 len -= rdlen;
173 }
174 res = close(fd);
175 if (res == -1) {
176 PERROR("close");
177 return -1;
178 }
179 return 0;
180}
181
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000182static int check_dir_contents(const char *path, const char **contents)
183{
184 int i;
185 int res;
186 int err = 0;;
187 int found[MAX_ENTRIES];
188 const char *cont[MAX_ENTRIES];
189 DIR *dp;
190
191 for (i = 0; contents[i]; i++) {
192 assert(i < MAX_ENTRIES - 3);
193 found[i] = 0;
194 cont[i] = contents[i];
195 }
196 found[i] = 0;
197 cont[i++] = ".";
198 found[i] = 0;
199 cont[i++] = "..";
200 cont[i] = NULL;
201
202 dp = opendir(path);
203 if (dp == NULL) {
204 PERROR("opendir");
205 return -1;
206 }
207 memset(found, 0, sizeof(found));
208 while(1) {
209 struct dirent *de;
210 errno = 0;
211 de = readdir(dp);
212 if (de == NULL) {
213 if (errno) {
214 PERROR("readdir");
215 closedir(dp);
216 return -1;
217 }
218 break;
219 }
220 for (i = 0; cont[i] != NULL; i++) {
221 assert(i < MAX_ENTRIES);
222 if (strcmp(cont[i], de->d_name) == 0) {
223 if (found[i]) {
224 ERROR("duplicate entry <%s>", de->d_name);
225 err--;
226 } else
227 found[i] = 1;
228 break;
229 }
230 }
231 if (!cont[i]) {
232 ERROR("unexpected entry <%s>", de->d_name);
233 err --;
234 }
235 }
236 for (i = 0; cont[i] != NULL; i++) {
237 if (!found[i]) {
238 ERROR("missing entry <%s>", cont[i]);
239 err--;
240 }
241 }
242 res = closedir(dp);
243 if (res == -1) {
244 PERROR("closedir");
245 return -1;
246 }
247 if (err)
248 return -1;
249
250 return 0;
251}
252
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000253static int create_file(const char *path, const char *data, int len)
254{
255 int res;
256 int fd;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000257
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000258 unlink(path);
259 fd = creat(path, 0644);
260 if (fd == -1) {
261 PERROR("creat");
262 return -1;
263 }
264 res = write(fd, data, len);
265 if (res == -1) {
266 PERROR("write");
267 close(fd);
268 return -1;
269 }
270 if (res != len) {
271 ERROR("write is short: %u instead of %u", res, len);
272 close(fd);
273 return -1;
274 }
275 res = close(fd);
276 if (res == -1) {
277 PERROR("close");
278 return -1;
279 }
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000280 res = check_type(path, S_IFREG);
281 if (res == -1)
282 return -1;
283 res = check_mode(path, 0644);
284 if (res == -1)
285 return -1;
286 res = check_nlink(path, 1);
287 if (res == -1)
288 return -1;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000289 res = check_size(path, len);
290 if (res == -1)
291 return -1;
292
293 res = check_data(path, data, 0, len);
294 if (res == -1)
295 return -1;
296
297 return 0;
298}
299
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000300static int cleanup_dir(const char *path, const char **dir_files, int quiet)
301{
302 int i;
303 int err = 0;
304
305 for (i = 0; dir_files[i]; i++) {
306 int res;
307 char fpath[1024];
308 sprintf(fpath, "%s/%s", path, dir_files[i]);
309 res = unlink(fpath);
310 if (res == -1 && !quiet) {
311 PERROR("unlink");
312 err --;
313 }
314 }
315 if (err)
316 return -1;
317
318 return 0;
319}
320
321static int create_dir(const char *path, const char **dir_files)
322{
323 int res;
324 int i;
325
326 rmdir(path);
327 res = mkdir(path, 0755);
328 if (res == -1) {
329 PERROR("mkdir");
330 return -1;
331 }
332 res = check_type(path, S_IFDIR);
333 if (res == -1)
334 return -1;
335 res = check_mode(path, 0755);
336 if (res == -1)
337 return -1;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000338
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000339 for (i = 0; dir_files[i]; i++) {
340 char fpath[1024];
341 sprintf(fpath, "%s/%s", path, dir_files[i]);
342 res = create_file(fpath, "", 0);
343 if (res == -1) {
344 cleanup_dir(path, dir_files, 1);
345 return -1;
346 }
347 }
348 res = check_dir_contents(path, dir_files);
349 if (res == -1) {
350 cleanup_dir(path, dir_files, 1);
351 return -1;
352 }
353
354 return 0;
355}
356
357
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000358int test_truncate(int len)
359{
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000360 const char *data = testdata;
361 int datalen = testdatalen;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000362 int res;
363
364 start_test("truncate(%u)", (int) len);
365 res = create_file(testfile, data, datalen);
366 if (res == -1)
367 return -1;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000368
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000369 res = truncate(testfile, len);
370 if (res == -1) {
371 PERROR("truncate");
372 return -1;
373 }
374 res = check_size(testfile, len);
375 if (res == -1)
376 return -1;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000377
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000378 if (len > 0) {
379 if (len <= datalen) {
380 res = check_data(testfile, data, 0, len);
381 if (res == -1)
382 return -1;
383 } else {
384 res = check_data(testfile, data, 0, datalen);
385 if (res == -1)
386 return -1;
387 res = check_data(testfile, zerodata, datalen, len - datalen);
388 if (res == -1)
389 return -1;
390 }
391 }
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000392 res = unlink(testfile);
393 if (res == -1) {
394 PERROR("unlink");
395 return -1;
396 }
397 res = check_nonexist(testfile2);
398 if (res == -1)
399 return -1;
400
401 success();
402 return 0;
403}
404
405static int test_create(void)
406{
407 const char *data = testdata;
408 int datalen = testdatalen;
409 int err = 0;
410 int res;
411 int fd;
412
413 start_test("create");
414 unlink(testfile);
415 fd = creat(testfile, 0644);
416 if (fd == -1) {
417 PERROR("creat");
418 return -1;
419 }
420 res = write(fd, data, datalen);
421 if (res == -1) {
422 PERROR("write");
423 close(fd);
424 return -1;
425 }
426 if (res != datalen) {
427 ERROR("write is short: %u instead of %u", res, datalen);
428 close(fd);
429 return -1;
430 }
431 res = close(fd);
432 if (res == -1) {
433 PERROR("close");
434 return -1;
435 }
436 res = check_type(testfile, S_IFREG);
437 if (res == -1)
438 return -1;
439 err += check_mode(testfile, 0644);
440 err += check_nlink(testfile, 1);
441 err += check_size(testfile, datalen);
442 err += check_data(testfile, data, 0, datalen);
443 res = unlink(testfile);
444 if (res == -1) {
445 PERROR("unlink");
446 return -1;
447 }
448 res = check_nonexist(testfile);
449 if (res == -1)
450 return -1;
451 if (err)
452 return -1;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000453
454 success();
455 return 0;
456}
457
458static int test_symlink(void)
459{
460 char buf[1024];
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000461 const char *data = testdata;
462 int datalen = testdatalen;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000463 int linklen = strlen(testfile);
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000464 int err = 0;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000465 int res;
466
467 start_test("symlink");
468 res = create_file(testfile, data, datalen);
469 if (res == -1)
470 return -1;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000471
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000472 unlink(testfile2);
473 res = symlink(testfile, testfile2);
474 if (res == -1) {
475 PERROR("symlink");
476 return -1;
477 }
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000478 res = check_type(testfile2, S_IFLNK);
479 if (res == -1)
480 return -1;
481 err += check_mode(testfile2, 0777);
482 err += check_nlink(testfile2, 1);
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000483 res = readlink(testfile2, buf, sizeof(buf));
484 if (res == -1) {
485 PERROR("readlink");
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000486 err--;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000487 }
488 if (res != linklen) {
489 ERROR("short readlink: %u instead of %u", res, linklen);
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000490 err--;
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000491 }
492 if (memcmp(buf, testfile, linklen) != 0) {
493 ERROR("link mismatch");
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000494 err--;
495 }
496 err += check_size(testfile2, datalen);
497 err += check_data(testfile2, data, 0, datalen);
498 res = unlink(testfile2);
499 if (res == -1) {
500 PERROR("unlink");
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000501 return -1;
502 }
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000503 res = check_nonexist(testfile2);
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000504 if (res == -1)
505 return -1;
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000506 if (err)
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000507 return -1;
508
509 success();
510 return 0;
511}
512
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000513static int test_rename_file(void)
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000514{
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000515 const char *data = testdata;
516 int datalen = testdatalen;
517 int err = 0;
518 int res;
519
520 start_test("rename file");
521 res = create_file(testfile, data, datalen);
522 if (res == -1)
523 return -1;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000524
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000525 unlink(testfile2);
526 res = rename(testfile, testfile2);
527 if (res == -1) {
528 PERROR("rename");
529 return -1;
530 }
531 res = check_nonexist(testfile);
532 if (res == -1)
533 return -1;
534 res = check_type(testfile2, S_IFREG);
535 if (res == -1)
536 return -1;
537 err += check_mode(testfile2, 0644);
538 err += check_nlink(testfile2, 1);
539 err += check_size(testfile2, datalen);
540 err += check_data(testfile2, data, 0, datalen);
541 res = unlink(testfile2);
542 if (res == -1) {
543 PERROR("unlink");
544 return -1;
545 }
546 res = check_nonexist(testfile2);
547 if (res == -1)
548 return -1;
549 if (err)
550 return -1;
551
552 success();
553 return 0;
554}
555
556static int test_rename_dir(void)
557{
558 int err = 0;
559 int res;
560
561 start_test("rename dir");
562 res = create_dir(testdir, testdir_files);
563 if (res == -1)
564 return -1;
Miklos Szeredi9b813af2005-07-21 07:59:37 +0000565
Miklos Szeredi0fc4abe2005-05-10 16:10:05 +0000566 rmdir(testdir2);
567 res = rename(testdir, testdir2);
568 if (res == -1) {
569 PERROR("rename");
570 cleanup_dir(testdir, testdir_files, 1);
571 return -1;
572 }
573 res = check_nonexist(testdir);
574 if (res == -1) {
575 cleanup_dir(testdir, testdir_files, 1);
576 return -1;
577 }
578 res = check_type(testdir2, S_IFDIR);
579 if (res == -1) {
580 cleanup_dir(testdir2, testdir_files, 1);
581 return -1;
582 }
583 err += check_mode(testdir2, 0755);
584 err += check_dir_contents(testdir2, testdir_files);
585 err += cleanup_dir(testdir2, testdir_files, 0);
586 res = rmdir(testdir2);
587 if (res == -1) {
588 PERROR("rmdir");
589 return -1;
590 }
591 res = check_nonexist(testdir2);
592 if (res == -1)
593 return -1;
594 if (err)
595 return -1;
596
597 success();
598 return 0;
599}
600
601int test_mkfifo(void)
602{
603 int res;
604 int err = 0;
605
606 start_test("mkfifo");
607 unlink(testfile);
608 res = mkfifo(testfile, 0644);
609 if (res == -1) {
610 PERROR("mkfifo");
611 return -1;
612 }
613 res = check_type(testfile, S_IFIFO);
614 if (res == -1)
615 return -1;
616 err += check_mode(testfile, 0644);
617 err += check_nlink(testfile, 1);
618 res = unlink(testfile);
619 if (res == -1) {
620 PERROR("unlink");
621 return -1;
622 }
623 res = check_nonexist(testfile);
624 if (res == -1)
625 return -1;
626 if (err)
627 return -1;
628
629 success();
630 return 0;
631}
632
633int test_mkdir(void)
634{
635 int res;
636 int err = 0;
637 const char *dir_contents[] = {NULL};
638
639 start_test("mkdir");
640 rmdir(testdir);
641 res = mkdir(testdir, 0755);
642 if (res == -1) {
643 PERROR("mkdir");
644 return -1;
645 }
646 res = check_type(testdir, S_IFDIR);
647 if (res == -1)
648 return -1;
649 err += check_mode(testdir, 0755);
650 err += check_nlink(testdir, 2);
651 err += check_dir_contents(testdir, dir_contents);
652 res = rmdir(testdir);
653 if (res == -1) {
654 PERROR("rmdir");
655 return -1;
656 }
657 res = check_nonexist(testdir);
658 if (res == -1)
659 return -1;
660 if (err)
661 return -1;
662
663 success();
664 return 0;
665}
666
667int main(int argc, char *argv[])
668{
669 const char *basepath;
670 int err = 0;
671
672 if (argc != 2) {
673 fprintf(stderr, "usage: %s testdir\n", argv[0]);
674 return 1;
675 }
676 basepath = argv[1];
677 assert(strlen(basepath) < 512);
678
679 sprintf(testfile, "%s/testfile", basepath);
680 sprintf(testfile2, "%s/testfile2", basepath);
681 sprintf(testdir, "%s/testdir", basepath);
682 sprintf(testdir2, "%s/testdir2", basepath);
683 err += test_create();
684 err += test_symlink();
685 err += test_mkfifo();
686 err += test_mkdir();
687 err += test_rename_file();
688 err += test_rename_dir();
689 err += test_truncate(0);
690 err += test_truncate(testdatalen / 2);
691 err += test_truncate(testdatalen);
692 err += test_truncate(testdatalen + 100);
693 unlink(testfile);
694 unlink(testfile2);
695 rmdir(testdir);
696 rmdir(testdir2);
697
698 if (err)
699 return 1;
700
Miklos Szeredi3b206c72005-05-06 10:15:26 +0000701 return 0;
702}