1 /* Tests for truncate(2) call family - by D.C. van Moolenbroek */
2 #define _POSIX_SOURCE 1
12 #define TESTFILE "testfile"
14 #define THRESHOLD 1048576
18 int main(int argc
, char *argv
[]);
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
));
27 void sub50e(off_t osize
, off_t nsize
);
29 void sub50f(off_t osize
, off_t nsize
);
31 void sub50g(off_t osize
, off_t nsize
);
33 void sub50h(off_t osize
, off_t nsize
);
35 void sub50i(off_t size
, off_t off
, size_t len
, int type
);
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
;
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();
72 return(-1); /* impossible */
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);
92 for (i
= 0; i
< largest
; i
++)
93 data
[i
] = (unsigned char) (rand() % 255 + 1);
97 void(*call
) (off_t osize
, off_t nsize
);
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
]);
112 if ((fd
= open(TESTFILE
, O_RDWR
|O_CREAT
|O_EXCL
, 0600)) < 0) e(1001);
116 r
= write(fd
, data
+ off
, size
- off
);
118 if (r
!= size
- off
) e(1002);
126 void check_file(fd
, hole_start
, hole_end
, size
)
132 static unsigned char buf
[16384];
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);
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);
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);
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);
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);
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);
229 if (unlink(TESTFILE
) != 0) e(12);
241 if ((fd
= open(TESTFILE
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0) e(1);
243 if (write(fd
, data
, TESTSIZE
) != TESTSIZE
) e(2);
246 if (lseek(fd
, off
, SEEK_SET
) != off
) e(3);
250 /* Negative sizes should result in EINVAL. */
251 flock
.l_whence
= SEEK_SET
;
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
;
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);
287 /* Calls on an invalid file descriptor should return EBADF or EINVAL. */
288 flock
.l_whence
= SEEK_SET
;
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);
301 if (unlink(TESTFILE
) != 0) e(23);
313 if ((fd
= open(TESTFILE
, O_WRONLY
|O_CREAT
|O_EXCL
, 0600)) < 0) e(1);
315 if (write(fd
, data
, TESTSIZE
) != TESTSIZE
) e(2);
318 if (lseek(fd
, off
, SEEK_SET
) != off
) e(3);
320 /* The given length must be positive. */
321 flock
.l_whence
= SEEK_CUR
;
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
;
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
;
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
;
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
;
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);
385 /* Calls on an invalid file descriptor should return EBADF or EINVAL. */
386 flock
.l_whence
= SEEK_SET
;
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);
399 if (unlink(TESTFILE
) != 0) e(29);
402 void sub50e(osize
, nsize
)
408 fd
= make_file(osize
);
410 if (truncate(TESTFILE
, nsize
) != 0) e(1);
412 check_file(fd
, osize
, nsize
, nsize
);
415 if (truncate(TESTFILE
, osize
) != 0) e(2);
417 check_file(fd
, nsize
, osize
, osize
);
422 if (unlink(TESTFILE
) != 0) e(3);
430 /* truncate(2) on a file that is open. */
434 void sub50f(osize
, nsize
)
440 fd
= make_file(osize
);
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
);
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
);
462 if (unlink(TESTFILE
) != 0) e(5);
469 /* truncate(2) on a file that is not open. */
473 void sub50g(osize
, nsize
)
479 fd
= make_file(osize
);
481 if (ftruncate(fd
, nsize
) != 0) e(1);
483 check_file(fd
, osize
, nsize
, nsize
);
486 if (ftruncate(fd
, osize
) != 0) e(2);
488 check_file(fd
, nsize
, osize
, osize
);
493 if (unlink(TESTFILE
) != 0) e(3);
500 /* ftruncate(2) on an open file. */
504 void sub50h(osize
, nsize
)
511 fd
= make_file(osize
);
513 flock
.l_whence
= SEEK_SET
;
514 flock
.l_start
= nsize
;
516 if (fcntl(fd
, F_FREESP
, &flock
) != 0) e(1);
518 check_file(fd
, osize
, nsize
, nsize
);
521 flock
.l_whence
= SEEK_SET
;
522 flock
.l_start
= osize
;
524 if (fcntl(fd
, F_FREESP
, &flock
) != 0) e(2);
526 check_file(fd
, nsize
, osize
, osize
);
531 if (unlink(TESTFILE
) != 0) e(3);
538 /* fcntl(2) with F_FREESP and l_len=0. */
542 void sub50i(size
, off
, len
, type
)
551 fd
= make_file(size
);
555 flock
.l_whence
= SEEK_SET
;
559 if (lseek(fd
, off
, SEEK_SET
) != off
) e(1);
560 flock
.l_whence
= SEEK_CUR
;
564 flock
.l_whence
= SEEK_END
;
565 flock
.l_start
= off
- size
;
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
;
582 if (fcntl(fd
, F_FREESP
, &flock
) != 0) e(3);
586 if (unlink(TESTFILE
) != 0) e(4);
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
])
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);