Drop main() prototype. Syncs with NetBSD-8
[minix.git] / minix / tests / test50.c
blob601891a3abc326f8e19108404d47e931db0eeb12
1 /* Tests for truncate(2) call family - by D.C. van Moolenbroek */
2 #include <sys/stat.h>
3 #include <sys/param.h>
4 #include <unistd.h>
5 #include <fcntl.h>
6 #include <assert.h>
8 #define ITERATIONS 1
9 int max_error = 4;
10 #include "common.h"
13 #define TESTFILE "testfile"
14 #define TESTSIZE 4096
15 #define THRESHOLD 1048576
18 int main(int argc, char *argv[]);
19 void prepare(void);
20 int make_file(off_t size);
21 void check_file(int fd, off_t size, off_t hole_start, off_t hole_end);
22 void all_sizes(void (*call) (off_t osize, off_t nsize));
23 void test50a(void);
24 void test50b(void);
25 void test50c(void);
26 void test50d(void);
27 void sub50e(off_t osize, off_t nsize);
28 void test50e(void);
29 void sub50f(off_t osize, off_t nsize);
30 void test50f(void);
31 void sub50g(off_t osize, off_t nsize);
32 void test50g(void);
33 void sub50h(off_t osize, off_t nsize);
34 void test50h(void);
35 void sub50i(off_t size, off_t off, size_t len, int type);
36 void test50i(void);
38 /* Some of the sizes have been chosen in such a way that they should be on the
39 * edge of direct/single indirect/double indirect switchovers for a MINIX
40 * file system with 4K block size.
42 static off_t sizes[] = {
43 0L, 1L, 511L, 512L, 513L, 1023L, 1024L, 1025L, 2047L, 2048L, 2049L, 3071L,
44 3072L, 3073L, 4095L, 4096L, 4097L, 16383L, 16384L, 16385L, 28671L, 28672L,
45 28673L, 65535L, 65536L, 65537L, 4222975L, 4222976L, 4222977L
48 static unsigned char *data;
50 int main(argc, argv)
51 int argc;
52 char *argv[];
54 int j, m = 0xFFFF;
56 start(50);
57 prepare();
58 if (argc == 2) m = atoi(argv[1]);
59 for (j = 0; j < ITERATIONS; j++) {
60 if (m & 00001) test50a();
61 if (m & 00002) test50b();
62 if (m & 00004) test50c();
63 if (m & 00010) test50d();
64 if (m & 00020) test50e();
65 if (m & 00040) test50f();
66 if (m & 00100) test50g();
67 if (m & 00200) test50h();
68 if (m & 00400) test50i();
71 quit();
72 return(-1); /* impossible */
75 void prepare()
77 size_t largest;
78 int i;
80 largest = 0;
81 for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++)
82 if (largest < sizes[i]) largest = sizes[i];
84 /* internal integrity check: this is needed for early tests */
85 assert(largest >= TESTSIZE);
87 data = malloc(largest);
88 if (data == NULL) e(1000);
90 srand(1);
92 for (i = 0; i < largest; i++)
93 data[i] = (unsigned char) (rand() % 255 + 1);
96 void all_sizes(call)
97 void(*call) (off_t osize, off_t nsize);
99 int i, j;
101 for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++)
102 for (j = 0; j < sizeof(sizes) / sizeof(sizes[0]); j++)
103 call(sizes[i], sizes[j]);
106 int make_file(size)
107 off_t size;
109 off_t off;
110 int fd, r;
112 if ((fd = open(TESTFILE, O_RDWR|O_CREAT|O_EXCL, 0600)) < 0) e(1001);
114 off = 0;
115 while (off < size) {
116 r = write(fd, data + off, size - off);
118 if (r != size - off) e(1002);
120 off += r;
123 return fd;
126 void check_file(fd, hole_start, hole_end, size)
127 int fd;
128 off_t hole_start;
129 off_t hole_end;
130 off_t size;
132 static unsigned char buf[16384];
133 struct stat statbuf;
134 off_t off;
135 int i, chunk;
137 /* The size must match. */
138 if (fstat(fd, &statbuf) != 0) e(1003);
139 if (statbuf.st_size != size) e(1004);
141 if (lseek(fd, 0L, SEEK_SET) != 0L) e(1005);
143 /* All bytes in the file must be equal to what we wrote, except for the bytes
144 * in the hole, which must be zero.
146 for (off = 0; off < size; off += chunk) {
147 chunk = MIN(sizeof(buf), size - off);
149 if (read(fd, buf, chunk) != chunk) e(1006);
151 for (i = 0; i < chunk; i++) {
152 if (off + i >= hole_start && off + i < hole_end) {
153 if (buf[i] != 0) e(1007);
155 else {
156 if (buf[i] != data[off+i]) e(1008);
161 /* We must get back EOF at the end. */
162 if (read(fd, buf, sizeof(buf)) != 0) e(1009);
165 void test50a()
167 struct stat statbuf;
168 int fd;
170 subtest = 1;
172 if ((fd = open(TESTFILE, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) e(1);
174 if (write(fd, data, TESTSIZE) != TESTSIZE) e(2);
176 /* Negative sizes should result in EINVAL. */
177 if (truncate(TESTFILE, -1) != -1) e(3);
178 if (errno != EINVAL) e(4);
180 /* Make sure the file size did not change. */
181 if (fstat(fd, &statbuf) != 0) e(5);
182 if (statbuf.st_size != TESTSIZE) e(6);
184 close(fd);
185 if (unlink(TESTFILE) != 0) e(7);
187 /* An empty path should result in ENOENT. */
188 if (truncate("", 0) != -1) e(8);
189 if (errno != ENOENT) e(9);
191 /* A non-existing file name should result in ENOENT. */
192 if (truncate(TESTFILE"2", 0) != -1) e(10);
193 if (errno != ENOENT) e(11);
196 void test50b()
198 struct stat statbuf;
199 int fd;
201 subtest = 2;
203 if ((fd = open(TESTFILE, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) e(1);
205 if (write(fd, data, TESTSIZE) != TESTSIZE) e(2);
207 /* Negative sizes should result in EINVAL. */
208 if (ftruncate(fd, -1) != -1) e(3);
209 if (errno != EINVAL) e(4);
211 /* Make sure the file size did not change. */
212 if (fstat(fd, &statbuf) != 0) e(5);
213 if (statbuf.st_size != TESTSIZE) e(6);
215 close(fd);
217 /* Calls on an invalid file descriptor should return EBADF or EINVAL. */
218 if (ftruncate(fd, 0) != -1) e(7);
219 if (errno != EBADF && errno != EINVAL) e(8);
221 if ((fd = open(TESTFILE, O_RDONLY)) < 0) e(9);
223 /* Calls on a file opened read-only should return EBADF or EINVAL. */
224 if (ftruncate(fd, 0) != -1) e(10);
225 if (errno != EBADF && errno != EINVAL) e(11);
227 close(fd);
229 if (unlink(TESTFILE) != 0) e(12);
232 void test50c()
234 struct stat statbuf;
235 struct flock flock;
236 off_t off;
237 int fd;
239 subtest = 3;
241 if ((fd = open(TESTFILE, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) e(1);
243 if (write(fd, data, TESTSIZE) != TESTSIZE) e(2);
245 off = TESTSIZE / 2;
246 if (lseek(fd, off, SEEK_SET) != off) e(3);
248 flock.l_len = 0;
250 /* Negative sizes should result in EINVAL. */
251 flock.l_whence = SEEK_SET;
252 flock.l_start = -1;
253 if (fcntl(fd, F_FREESP, &flock) != -1) e(4);
254 if (errno != EINVAL) e(5);
256 flock.l_whence = SEEK_CUR;
257 flock.l_start = -off - 1;
258 if (fcntl(fd, F_FREESP, &flock) != -1) e(6);
259 if (errno != EINVAL) e(7);
261 flock.l_whence = SEEK_END;
262 flock.l_start = -TESTSIZE - 1;
263 if (fcntl(fd, F_FREESP, &flock) != -1) e(8);
264 if (errno != EINVAL) e(9);
266 /* Make sure the file size did not change. */
267 if (fstat(fd, &statbuf) != 0) e(10);
268 if (statbuf.st_size != TESTSIZE) e(11);
270 /* Proper negative values should work, however. */
271 flock.l_whence = SEEK_CUR;
272 flock.l_start = -1;
273 if (fcntl(fd, F_FREESP, &flock) != 0) e(12);
275 if (fstat(fd, &statbuf) != 0) e(13);
276 if (statbuf.st_size != off - 1) e(14);
278 flock.l_whence = SEEK_END;
279 flock.l_start = -off + 1;
280 if (fcntl(fd, F_FREESP, &flock) != 0) e(15);
282 if (fstat(fd, &statbuf) != 0) e(16);
283 if (statbuf.st_size != 0L) e(17);
285 close(fd);
287 /* Calls on an invalid file descriptor should return EBADF or EINVAL. */
288 flock.l_whence = SEEK_SET;
289 flock.l_start = 0;
290 if (fcntl(fd, F_FREESP, &flock) != -1) e(18);
291 if (errno != EBADF && errno != EINVAL) e(19);
293 if ((fd = open(TESTFILE, O_RDONLY)) < 0) e(20);
295 /* Calls on a file opened read-only should return EBADF or EINVAL. */
296 if (fcntl(fd, F_FREESP, &flock) != -1) e(21);
297 if (errno != EBADF && errno != EINVAL) e(22);
299 close(fd);
301 if (unlink(TESTFILE) != 0) e(23);
304 void test50d()
306 struct stat statbuf;
307 struct flock flock;
308 off_t off;
309 int fd;
311 subtest = 4;
313 if ((fd = open(TESTFILE, O_WRONLY|O_CREAT|O_EXCL, 0600)) < 0) e(1);
315 if (write(fd, data, TESTSIZE) != TESTSIZE) e(2);
317 off = TESTSIZE / 2;
318 if (lseek(fd, off, SEEK_SET) != off) e(3);
320 /* The given length must be positive. */
321 flock.l_whence = SEEK_CUR;
322 flock.l_start = 0;
323 flock.l_len = -1;
324 if (fcntl(fd, F_FREESP, &flock) != -1) e(4);
325 if (errno != EINVAL) e(5);
327 /* Negative start positions are not allowed. */
328 flock.l_whence = SEEK_SET;
329 flock.l_start = -1;
330 flock.l_len = 1;
331 if (fcntl(fd, F_FREESP, &flock) != -1) e(6);
332 if (errno != EINVAL) e(7);
334 flock.l_whence = SEEK_CUR;
335 flock.l_start = -off - 1;
336 if (fcntl(fd, F_FREESP, &flock) != -1) e(8);
337 if (errno != EINVAL) e(9);
339 flock.l_whence = SEEK_END;
340 flock.l_start = -TESTSIZE - 1;
341 if (fcntl(fd, F_FREESP, &flock) != -1) e(10);
342 if (errno != EINVAL) e(11);
344 /* Start positions at or beyond the end of the file are no good, either. */
345 flock.l_whence = SEEK_SET;
346 flock.l_start = TESTSIZE;
347 if (fcntl(fd, F_FREESP, &flock) != -1) e(12);
348 if (errno != EINVAL) e(13);
350 flock.l_start = TESTSIZE + 1;
351 if (fcntl(fd, F_FREESP, &flock) != -1) e(13);
352 if (errno != EINVAL) e(14);
354 flock.l_whence = SEEK_CUR;
355 flock.l_start = TESTSIZE - off;
356 if (fcntl(fd, F_FREESP, &flock) != -1) e(15);
357 if (errno != EINVAL) e(16);
359 flock.l_whence = SEEK_END;
360 flock.l_start = 1;
361 if (fcntl(fd, F_FREESP, &flock) != -1) e(17);
362 if (errno != EINVAL) e(18);
364 /* End positions beyond the end of the file may be silently bounded. */
365 flock.l_whence = SEEK_SET;
366 flock.l_start = 0;
367 flock.l_len = TESTSIZE + 1;
368 if (fcntl(fd, F_FREESP, &flock) != 0) e(19);
370 flock.l_whence = SEEK_CUR;
371 flock.l_len = TESTSIZE - off + 1;
372 if (fcntl(fd, F_FREESP, &flock) != 0) e(20);
374 flock.l_whence = SEEK_END;
375 flock.l_start = -1;
376 flock.l_len = 2;
377 if (fcntl(fd, F_FREESP, &flock) != 0) e(21);
379 /* However, this must never cause the file size to change. */
380 if (fstat(fd, &statbuf) != 0) e(22);
381 if (statbuf.st_size != TESTSIZE) e(23);
383 close(fd);
385 /* Calls on an invalid file descriptor should return EBADF or EINVAL. */
386 flock.l_whence = SEEK_SET;
387 flock.l_start = 0;
388 if (fcntl(fd, F_FREESP, &flock) != -1) e(24);
389 if (errno != EBADF && errno != EINVAL) e(25);
391 if ((fd = open(TESTFILE, O_RDONLY)) < 0) e(26);
393 /* Calls on a file opened read-only should return EBADF or EINVAL. */
394 if (fcntl(fd, F_FREESP, &flock) != -1) e(27);
395 if (errno != EBADF && errno != EINVAL) e(28);
397 close(fd);
399 if (unlink(TESTFILE) != 0) e(29);
402 void sub50e(osize, nsize)
403 off_t osize;
404 off_t nsize;
406 int fd;
408 fd = make_file(osize);
410 if (truncate(TESTFILE, nsize) != 0) e(1);
412 check_file(fd, osize, nsize, nsize);
414 if (nsize < osize) {
415 if (truncate(TESTFILE, osize) != 0) e(2);
417 check_file(fd, nsize, osize, osize);
420 close(fd);
422 if (unlink(TESTFILE) != 0) e(3);
426 void test50e()
428 subtest = 5;
430 /* truncate(2) on a file that is open. */
431 all_sizes(sub50e);
434 void sub50f(osize, nsize)
435 off_t osize;
436 off_t nsize;
438 int fd;
440 fd = make_file(osize);
442 close(fd);
444 if (truncate(TESTFILE, nsize) != 0) e(1);
446 if ((fd = open(TESTFILE, O_RDONLY)) < 0) e(2);
448 check_file(fd, osize, nsize, nsize);
450 if (nsize < osize) {
451 close(fd);
453 if (truncate(TESTFILE, osize) != 0) e(3);
455 if ((fd = open(TESTFILE, O_RDONLY)) < 0) e(4);
457 check_file(fd, nsize, osize, osize);
460 close(fd);
462 if (unlink(TESTFILE) != 0) e(5);
465 void test50f()
467 subtest = 6;
469 /* truncate(2) on a file that is not open. */
470 all_sizes(sub50f);
473 void sub50g(osize, nsize)
474 off_t osize;
475 off_t nsize;
477 int fd;
479 fd = make_file(osize);
481 if (ftruncate(fd, nsize) != 0) e(1);
483 check_file(fd, osize, nsize, nsize);
485 if (nsize < osize) {
486 if (ftruncate(fd, osize) != 0) e(2);
488 check_file(fd, nsize, osize, osize);
491 close(fd);
493 if (unlink(TESTFILE) != 0) e(3);
496 void test50g()
498 subtest = 7;
500 /* ftruncate(2) on an open file. */
501 all_sizes(sub50g);
504 void sub50h(osize, nsize)
505 off_t osize;
506 off_t nsize;
508 struct flock flock;
509 int fd;
511 fd = make_file(osize);
513 flock.l_whence = SEEK_SET;
514 flock.l_start = nsize;
515 flock.l_len = 0;
516 if (fcntl(fd, F_FREESP, &flock) != 0) e(1);
518 check_file(fd, osize, nsize, nsize);
520 if (nsize < osize) {
521 flock.l_whence = SEEK_SET;
522 flock.l_start = osize;
523 flock.l_len = 0;
524 if (fcntl(fd, F_FREESP, &flock) != 0) e(2);
526 check_file(fd, nsize, osize, osize);
529 close(fd);
531 if (unlink(TESTFILE) != 0) e(3);
534 void test50h()
536 subtest = 8;
538 /* fcntl(2) with F_FREESP and l_len=0. */
539 all_sizes(sub50h);
542 void sub50i(size, off, len, type)
543 off_t size;
544 off_t off;
545 size_t len;
546 int type;
548 struct flock flock;
549 int fd;
551 fd = make_file(size);
553 switch (type) {
554 case 0:
555 flock.l_whence = SEEK_SET;
556 flock.l_start = off;
557 break;
558 case 1:
559 if (lseek(fd, off, SEEK_SET) != off) e(1);
560 flock.l_whence = SEEK_CUR;
561 flock.l_start = 0;
562 break;
563 case 2:
564 flock.l_whence = SEEK_END;
565 flock.l_start = off - size;
566 break;
567 default:
568 e(1);
571 flock.l_len = len;
572 if (fcntl(fd, F_FREESP, &flock) != 0) e(2);
574 check_file(fd, off, off + len, size);
576 /* Repeat the call in order to see whether the file system can handle holes
577 * while freeing up. If not, the server would typically crash; we need not
578 * check the results again.
580 flock.l_whence = SEEK_SET;
581 flock.l_start = off;
582 if (fcntl(fd, F_FREESP, &flock) != 0) e(3);
584 close(fd);
586 if (unlink(TESTFILE) != 0) e(4);
589 void test50i()
591 off_t off;
592 int i, j, k, l;
594 subtest = 9;
596 /* fcntl(2) with F_FREESP and l_len>0. */
598 /* This loop determines the size of the test file. */
599 for (i = 0; i < sizeof(sizes) / sizeof(sizes[0]); i++) {
600 /* Big files simply take too long. We have to compromise here. */
601 if (sizes[i] >= THRESHOLD) continue;
603 /* This loop determines one of the two values for the offset. */
604 for (j = 0; j < sizeof(sizes) / sizeof(sizes[0]); j++) {
605 if (sizes[j] >= sizes[i]) continue;
607 /* This loop determines the other. */
608 for (k = 0; k < sizeof(sizes) / sizeof(sizes[0]); k++) {
609 if (sizes[k] > sizes[j]) continue;
611 /* Construct an offset by adding the two sizes. */
612 off = sizes[j] + sizes[k];
614 if (j + 1 < sizeof(sizes) / sizeof(sizes[0]) &&
615 off >= sizes[j + 1]) continue;
617 /* This loop determines the length of the hole. */
618 for (l = 0; l < sizeof(sizes) / sizeof(sizes[0]); l++) {
619 if (sizes[l] == 0 || off + sizes[l] > sizes[i])
620 continue;
622 /* This could have been a loop, too! */
623 sub50i(sizes[i], off, sizes[l], 0);
624 sub50i(sizes[i], off, sizes[l], 1);
625 sub50i(sizes[i], off, sizes[l], 2);