1 /* Tests for copy_file_range.
2 Copyright (C) 2017-2018 Free Software Foundation, Inc.
3 This file is part of the GNU C Library.
5 The GNU C Library is free software; you can redistribute it and/or
6 modify it under the terms of the GNU Lesser General Public
7 License as published by the Free Software Foundation; either
8 version 2.1 of the License, or (at your option) any later version.
10 The GNU C Library is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with the GNU C Library; if not, see
17 <http://www.gnu.org/licenses/>. */
19 #include <array_length.h>
30 #include <support/check.h>
31 #include <support/namespace.h>
32 #include <support/support.h>
33 #include <support/temp_file.h>
34 #include <support/test-driver.h>
35 #include <support/xunistd.h>
37 # include <sys/mount.h>
40 /* Boolean flags which indicate whether to use pointers with explicit
45 /* Name and descriptors of the input files. Files are truncated and
46 reopened (with O_RDWR) between tests. */
52 /* Like the above, but on a different file system. xdevfile can be
53 NULL if no suitable file system has been found. */
54 static char *xdevfile
;
56 /* Input and output offsets. Set according to do_inoff and do_outoff
57 before the test. The offsets themselves are always set to
60 static off64_t
*pinoff
;
61 static off64_t outoff
;
62 static off64_t
*poutoff
;
64 /* These are a collection of copy sizes used in tests. The selection
65 takes into account that the fallback implementation uses an
66 internal buffer of 8192 bytes. */
67 enum { maximum_size
= 99999 };
68 static const int typical_sizes
[] =
69 { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
72 /* The random contents of this array can be used as a pattern to check
73 for correct write operations. */
74 static unsigned char random_data
[maximum_size
];
76 /* The size chosen by the test harness. */
77 static int current_size
;
79 /* Maximum writable file offset. Updated by find_maximum_offset
81 static off64_t maximum_offset
;
83 /* Error code when crossing the offset. */
84 static int maximum_offset_errno
;
86 /* If true: Writes which cross the limit will fail. If false: Writes
87 which cross the limit will result in a partial write. */
88 static bool maximum_offset_hard_limit
;
90 /* Fills maximum_offset etc. above. Truncates outfd as a side
93 find_maximum_offset (void)
95 xftruncate (outfd
, 0);
96 if (maximum_offset
!= 0)
100 upper
>>= 1; /* Maximum of off64_t. */
101 TEST_VERIFY ((off64_t
) upper
> 0);
102 TEST_VERIFY ((off64_t
) (upper
+ 1) < 0);
103 if (lseek64 (outfd
, upper
, SEEK_SET
) >= 0)
105 if (write (outfd
, "", 1) == 1)
106 FAIL_EXIT1 ("created a file larger than the off64_t range");
109 uint64_t lower
= 1024 * 1024; /* A reasonable minimum file size. */
110 /* Loop invariant: writing at lower succeeds, writing at upper fails. */
111 while (lower
+ 1 < upper
)
113 uint64_t middle
= (lower
+ upper
) / 2;
114 if (test_verbose
> 0)
115 printf ("info: %s: remaining test range %" PRIu64
" .. %" PRIu64
116 ", probe at %" PRIu64
"\n", __func__
, lower
, upper
, middle
);
117 xftruncate (outfd
, 0);
118 if (lseek64 (outfd
, middle
, SEEK_SET
) >= 0
119 && write (outfd
, "", 1) == 1)
124 TEST_VERIFY (lower
+ 1 == upper
);
125 maximum_offset
= lower
;
126 printf ("info: maximum writable file offset: %" PRIu64
" (%" PRIx64
")\n",
129 /* Check that writing at the valid offset actually works. */
130 xftruncate (outfd
, 0);
131 xlseek (outfd
, lower
, SEEK_SET
);
132 TEST_COMPARE (write (outfd
, "", 1), 1);
134 /* Cross the boundary with a two-byte write. This can either result
135 in a short write, or a failure. */
136 xlseek (outfd
, lower
, SEEK_SET
);
137 ssize_t ret
= write (outfd
, " ", 2);
140 maximum_offset_errno
= errno
;
141 maximum_offset_hard_limit
= true;
144 maximum_offset_hard_limit
= false;
146 /* Check that writing at the next offset actually fails. This also
147 obtains the expected errno value. */
148 xftruncate (outfd
, 0);
150 if (lseek64 (outfd
, lower
+ 1, SEEK_SET
) != 0)
152 if (write (outfd
, "", 1) != -1)
153 FAIL_EXIT1 ("write to impossible offset %" PRIu64
" succeeded",
156 int errno_copy
= errno
;
157 if (maximum_offset_hard_limit
)
158 TEST_COMPARE (errno_copy
, maximum_offset_errno
);
160 maximum_offset_errno
= errno_copy
;
165 maximum_offset_errno
= errno
;
167 printf ("info: %s out of range fails with %m (%d)\n",
168 action
, maximum_offset_errno
);
170 xftruncate (outfd
, 0);
171 xlseek (outfd
, 0, SEEK_SET
);
174 /* Perform a copy of a file. */
176 simple_file_copy (void)
178 xwrite (infd
, random_data
, current_size
);
181 int in_skipped
; /* Expected skipped bytes in input. */
184 xlseek (infd
, 1, SEEK_SET
);
186 length
= current_size
- 3;
191 xlseek (infd
, 3, SEEK_SET
);
192 length
= current_size
- 5;
195 int out_skipped
; /* Expected skipped bytes before the written data. */
198 xlseek (outfd
, 4, SEEK_SET
);
204 xlseek (outfd
, 6, SEEK_SET
);
205 length
= current_size
- 6;
211 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
215 TEST_COMPARE (inoff
, 2 + length
);
216 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 1);
219 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 3 + length
);
222 TEST_COMPARE (outoff
, 5 + length
);
223 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 4);
226 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 6 + length
);
231 TEST_COMPARE (st
.st_size
, out_skipped
+ length
);
234 /* If we did not write anything, we also did not add any
236 TEST_COMPARE (st
.st_size
, 0);
240 xlseek (outfd
, 0, SEEK_SET
);
241 char *bytes
= xmalloc (st
.st_size
);
242 TEST_COMPARE (read (outfd
, bytes
, st
.st_size
), st
.st_size
);
243 for (int i
= 0; i
< out_skipped
; ++i
)
244 TEST_COMPARE (bytes
[i
], 0);
245 TEST_VERIFY (memcmp (bytes
+ out_skipped
, random_data
+ in_skipped
,
250 /* Test that reading from a pipe willfails. */
252 pipe_as_source (void)
257 for (int length
= 0; length
< 2; ++length
)
259 if (test_verbose
> 0)
260 printf ("info: %s: length=%d\n", __func__
, length
);
262 /* Make sure that there is something to copy in the pipe. */
263 xwrite (pipefds
[1], "@", 1);
265 TEST_COMPARE (copy_file_range (pipefds
[0], pinoff
, outfd
, poutoff
,
267 /* Linux 4.10 and later return EINVAL. Older kernels return
269 TEST_VERIFY (errno
== EINVAL
|| errno
== EXDEV
);
270 TEST_COMPARE (inoff
, 0);
271 TEST_COMPARE (outoff
, 0);
272 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
274 /* Make sure that nothing was read. */
276 TEST_COMPARE (read (pipefds
[0], &buf
, 1), 1);
277 TEST_COMPARE (buf
, '@');
284 /* Test that writing to a pipe fails. */
286 pipe_as_destination (void)
288 /* Make sure that there is something to read in the input file. */
289 xwrite (infd
, "abc", 3);
290 xlseek (infd
, 0, SEEK_SET
);
295 for (int length
= 0; length
< 2; ++length
)
297 if (test_verbose
> 0)
298 printf ("info: %s: length=%d\n", __func__
, length
);
300 TEST_COMPARE (copy_file_range (infd
, pinoff
, pipefds
[1], poutoff
,
302 /* Linux 4.10 and later return EINVAL. Older kernels return
304 TEST_VERIFY (errno
== EINVAL
|| errno
== EXDEV
);
305 TEST_COMPARE (inoff
, 0);
306 TEST_COMPARE (outoff
, 0);
307 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
309 /* Make sure that nothing was written. */
310 struct pollfd pollfd
= { .fd
= pipefds
[0], .events
= POLLIN
, };
311 TEST_COMPARE (poll (&pollfd
, 1, 0), 0);
318 /* Test a write failure after (potentially) writing some bytes.
319 Failure occurs near the start of the buffer. */
321 delayed_write_failure_beginning (void)
323 /* We need to write something to provoke the error. */
324 if (current_size
== 0)
326 xwrite (infd
, random_data
, sizeof (random_data
));
327 xlseek (infd
, 0, SEEK_SET
);
329 /* Write failure near the start. The actual error code varies among
331 find_maximum_offset ();
332 off64_t where
= maximum_offset
;
334 if (current_size
== 1)
338 xlseek (outfd
, 1, SEEK_SET
);
340 xlseek (outfd
, where
, SEEK_SET
);
341 if (maximum_offset_hard_limit
|| where
> maximum_offset
)
343 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
344 sizeof (random_data
), 0), -1);
345 TEST_COMPARE (errno
, maximum_offset_errno
);
346 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
347 TEST_COMPARE (inoff
, 0);
349 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 1);
351 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), where
);
352 TEST_COMPARE (outoff
, where
);
355 TEST_COMPARE (st
.st_size
, 0);
359 /* The offset is not a hard limit. This means we write one
361 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
362 sizeof (random_data
), 0), 1);
365 TEST_COMPARE (inoff
, 1);
366 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
370 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 1);
371 TEST_COMPARE (inoff
, 0);
375 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 1);
376 TEST_COMPARE (outoff
, where
+ 1);
380 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), where
+ 1);
381 TEST_COMPARE (outoff
, where
);
385 TEST_COMPARE (st
.st_size
, where
+ 1);
389 /* Test a write failure after (potentially) writing some bytes.
390 Failure occurs near the end of the buffer. */
392 delayed_write_failure_end (void)
394 if (current_size
<= 1)
395 /* This would be same as the first test because there is not
396 enough data to write to make a difference. */
398 xwrite (infd
, random_data
, sizeof (random_data
));
399 xlseek (infd
, 0, SEEK_SET
);
401 find_maximum_offset ();
402 off64_t where
= maximum_offset
- current_size
+ 1;
403 if (current_size
== sizeof (random_data
))
404 /* Otherwise we do not reach the non-writable byte. */
408 xlseek (outfd
, 1, SEEK_SET
);
410 xlseek (outfd
, where
, SEEK_SET
);
411 ssize_t ret
= copy_file_range (infd
, pinoff
, outfd
, poutoff
,
412 sizeof (random_data
), 0);
415 TEST_COMPARE (ret
, -1);
416 TEST_COMPARE (errno
, maximum_offset_errno
);
419 TEST_COMPARE (st
.st_size
, 0);
423 /* The first copy succeeded. This happens in the emulation
424 because the internal buffer of limited size does not
425 necessarily cross the off64_t boundary on the first write
427 if (test_verbose
> 0)
428 printf ("info: copy_file_range (%zu) returned %zd\n",
429 sizeof (random_data
), ret
);
430 TEST_VERIFY (ret
> 0);
431 TEST_VERIFY (ret
< maximum_size
);
434 TEST_COMPARE (st
.st_size
, where
+ ret
);
437 TEST_COMPARE (inoff
, ret
);
438 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
441 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), ret
);
443 char *buffer
= xmalloc (ret
);
444 TEST_COMPARE (pread64 (outfd
, buffer
, ret
, where
), ret
);
445 TEST_VERIFY (memcmp (buffer
, random_data
, ret
) == 0);
448 /* The second copy fails. */
449 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
450 sizeof (random_data
), 0), -1);
451 TEST_COMPARE (errno
, maximum_offset_errno
);
455 /* Test a write failure across devices. */
457 cross_device_failure (void)
459 if (xdevfile
== NULL
)
460 /* Subtest not supported due to missing cross-device file. */
463 /* We need something to write. */
464 xwrite (infd
, random_data
, sizeof (random_data
));
465 xlseek (infd
, 0, SEEK_SET
);
467 int xdevfd
= xopen (xdevfile
, O_RDWR
| O_LARGEFILE
, 0);
468 TEST_COMPARE (copy_file_range (infd
, pinoff
, xdevfd
, poutoff
,
469 current_size
, 0), -1);
470 TEST_COMPARE (errno
, EXDEV
);
471 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
473 xfstat (xdevfd
, &st
);
474 TEST_COMPARE (st
.st_size
, 0);
479 /* Try to exercise ENOSPC behavior with a tempfs file system (so that
480 we do not have to fill up a regular file system to get the error).
481 This function runs in a subprocess, so that we do not change the
482 mount namespace of the actual test process. */
484 enospc_failure_1 (void *closure
)
487 support_become_root ();
489 /* Make sure that we do not alter the file system mounts of the
491 if (! support_enter_mount_namespace ())
493 printf ("warning: ENOSPC test skipped\n");
497 char *mountpoint
= closure
;
498 if (mount ("none", mountpoint
, "tmpfs", MS_NODEV
| MS_NOEXEC
,
501 printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint
);
505 /* The source file must reside on the same file system. */
506 char *intmpfsfile
= xasprintf ("%s/%s", mountpoint
, "in");
507 int intmpfsfd
= xopen (intmpfsfile
, O_RDWR
| O_CREAT
| O_LARGEFILE
, 0600);
508 xwrite (intmpfsfd
, random_data
, sizeof (random_data
));
509 xlseek (intmpfsfd
, 1, SEEK_SET
);
512 char *outtmpfsfile
= xasprintf ("%s/%s", mountpoint
, "out");
513 int outtmpfsfd
= xopen (outtmpfsfile
, O_RDWR
| O_CREAT
| O_LARGEFILE
, 0600);
515 /* Fill the file with data until ENOSPC is reached. */
518 ssize_t ret
= write (outtmpfsfd
, random_data
, sizeof (random_data
));
519 if (ret
< 0 && errno
!= ENOSPC
)
520 FAIL_EXIT1 ("write to %s: %m", outtmpfsfile
);
521 if (ret
< sizeof (random_data
))
524 TEST_COMPARE (write (outtmpfsfd
, "", 1), -1);
525 TEST_COMPARE (errno
, ENOSPC
);
526 off64_t maxsize
= xlseek (outtmpfsfd
, 0, SEEK_CUR
);
527 TEST_VERIFY_EXIT (maxsize
> sizeof (random_data
));
529 /* Constructed the expected file contents. */
530 char *expected
= xmalloc (maxsize
);
531 TEST_COMPARE (pread64 (outtmpfsfd
, expected
, maxsize
, 0), maxsize
);
532 /* Go back a little, so some bytes can be written. */
533 enum { offset
= 20000 };
534 TEST_VERIFY_EXIT (offset
< maxsize
);
535 TEST_VERIFY_EXIT (offset
< sizeof (random_data
));
536 memcpy (expected
+ maxsize
- offset
, random_data
+ 1, offset
);
540 outoff
= maxsize
- offset
;
541 xlseek (outtmpfsfd
, 2, SEEK_SET
);
544 xlseek (outtmpfsfd
, -offset
, SEEK_CUR
);
546 /* First call is expected to succeed because we made room for some
548 TEST_COMPARE (copy_file_range (intmpfsfd
, pinoff
, outtmpfsfd
, poutoff
,
549 maximum_size
, 0), offset
);
552 TEST_COMPARE (inoff
, 1 + offset
);
553 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1);
556 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1 + offset
);
559 TEST_COMPARE (outoff
, maxsize
);
560 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), 2);
563 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), maxsize
);
565 xfstat (outtmpfsfd
, &st
);
566 TEST_COMPARE (st
.st_size
, maxsize
);
567 char *actual
= xmalloc (st
.st_size
);
568 TEST_COMPARE (pread64 (outtmpfsfd
, actual
, st
.st_size
, 0), st
.st_size
);
569 TEST_VERIFY (memcmp (expected
, actual
, maxsize
) == 0);
571 /* Second call should fail with ENOSPC. */
572 TEST_COMPARE (copy_file_range (intmpfsfd
, pinoff
, outtmpfsfd
, poutoff
,
573 maximum_size
, 0), -1);
574 TEST_COMPARE (errno
, ENOSPC
);
576 /* Offsets should be unchanged. */
579 TEST_COMPARE (inoff
, 1 + offset
);
580 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1);
583 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1 + offset
);
586 TEST_COMPARE (outoff
, maxsize
);
587 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), 2);
590 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), maxsize
);
591 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_END
), maxsize
);
592 TEST_COMPARE (pread64 (outtmpfsfd
, actual
, maxsize
, 0), maxsize
);
593 TEST_VERIFY (memcmp (expected
, actual
, maxsize
) == 0);
603 #else /* !CLONE_NEWNS */
604 puts ("warning: ENOSPC test skipped (no mount namespaces)");
608 /* Call enospc_failure_1 in a subprocess. */
610 enospc_failure (void)
613 = support_create_temp_directory ("tst-copy_file_range-enospc-");
614 support_isolate_in_subprocess (enospc_failure_1
, mountpoint
);
618 /* The target file descriptor must have O_APPEND enabled. */
620 oappend_failure (void)
622 /* Add data, to make sure we do not fail because there is
623 insufficient input data. */
624 xwrite (infd
, random_data
, current_size
);
625 xlseek (infd
, 0, SEEK_SET
);
628 outfd
= xopen (outfile
, O_RDWR
| O_APPEND
, 0);
629 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
630 current_size
, 0), -1);
631 TEST_COMPARE (errno
, EBADF
);
634 /* Test that a short input file results in a shortened copy. */
638 if (current_size
== 0)
639 /* Nothing to shorten. */
642 /* Two subtests, one with offset 0 and current_size - 1 bytes, and
643 another one with current_size bytes, but offset 1. */
644 for (int shift
= 0; shift
< 2; ++shift
)
646 if (test_verbose
> 0)
647 printf ("info: shift=%d\n", shift
);
648 xftruncate (infd
, 0);
649 xlseek (infd
, 0, SEEK_SET
);
650 xwrite (infd
, random_data
, current_size
- !shift
);
655 xlseek (infd
, 2, SEEK_SET
);
660 xlseek (infd
, shift
, SEEK_SET
);
662 ftruncate (outfd
, 0);
663 xlseek (outfd
, 0, SEEK_SET
);
666 /* First call copies current_size - 1 bytes. */
667 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
668 current_size
, 0), current_size
- 1);
669 char *buffer
= xmalloc (current_size
);
670 TEST_COMPARE (pread64 (outfd
, buffer
, current_size
, 0),
672 TEST_VERIFY (memcmp (buffer
, random_data
+ shift
, current_size
- 1)
678 TEST_COMPARE (inoff
, current_size
- 1 + shift
);
679 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 2);
682 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), current_size
- 1 + shift
);
685 TEST_COMPARE (outoff
, current_size
- 1);
686 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
689 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), current_size
- 1);
691 /* First call copies zero bytes. */
692 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
693 current_size
, 0), 0);
694 /* And the offsets are unchanged. */
697 TEST_COMPARE (inoff
, current_size
- 1 + shift
);
698 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 2);
701 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), current_size
- 1 + shift
);
704 TEST_COMPARE (outoff
, current_size
- 1);
705 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
708 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), current_size
- 1);
712 /* A named test function. */
717 bool sizes
; /* If true, call the test with different current_size values. */
720 /* The available test cases. */
721 static struct test_case tests
[] =
723 { "simple_file_copy", simple_file_copy
, .sizes
= true },
724 { "pipe_as_source", pipe_as_source
, },
725 { "pipe_as_destination", pipe_as_destination
, },
726 { "delayed_write_failure_beginning", delayed_write_failure_beginning
,
728 { "delayed_write_failure_end", delayed_write_failure_end
, .sizes
= true },
729 { "cross_device_failure", cross_device_failure
, .sizes
= true },
730 { "enospc_failure", enospc_failure
, },
731 { "oappend_failure", oappend_failure
, .sizes
= true },
732 { "short_copy", short_copy
, .sizes
= true },
738 for (unsigned char *p
= random_data
; p
< array_end (random_data
); ++p
)
741 infd
= create_temp_file ("tst-copy_file_range-in-", &infile
);
743 int outfd
= create_temp_file ("tst-copy_file_range-out-", &outfile
);
744 if (!support_descriptor_supports_holes (outfd
))
745 FAIL_UNSUPPORTED ("File %s does not support holes", outfile
);
749 /* Try to find a different directory from the default input/output
752 struct stat64 instat
;
753 xfstat (infd
, &instat
);
754 static const char *const candidates
[] =
755 { NULL
, "/var/tmp", "/dev/shm" };
756 for (const char *const *c
= candidates
; c
< array_end (candidates
); ++c
)
758 const char *path
= *c
;
759 char *to_free
= NULL
;
762 to_free
= xreadlink ("/proc/self/exe");
763 path
= dirname (to_free
);
767 xstat (path
, &cstat
);
768 if (cstat
.st_dev
== instat
.st_dev
)
774 printf ("info: using alternate temporary files directory: %s\n", path
);
775 xdevfile
= xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path
);
779 if (xdevfile
!= NULL
)
781 int xdevfd
= mkstemp (xdevfile
);
783 FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile
);
784 struct stat64 xdevst
;
785 xfstat (xdevfd
, &xdevst
);
786 TEST_VERIFY (xdevst
.st_dev
!= instat
.st_dev
);
787 add_temp_file (xdevfile
);
791 puts ("warning: no alternate directory on different file system found");
795 for (do_inoff
= 0; do_inoff
< 2; ++do_inoff
)
796 for (do_outoff
= 0; do_outoff
< 2; ++do_outoff
)
797 for (struct test_case
*test
= tests
; test
< array_end (tests
); ++test
)
798 for (const int *size
= typical_sizes
;
799 size
< array_end (typical_sizes
); ++size
)
801 current_size
= *size
;
802 if (test_verbose
> 0)
803 printf ("info: %s do_inoff=%d do_outoff=%d current_size=%d\n",
804 test
->name
, do_inoff
, do_outoff
, current_size
);
817 infd
= xopen (infile
, O_RDWR
| O_LARGEFILE
, 0);
818 xftruncate (infd
, 0);
819 outfd
= xopen (outfile
, O_RDWR
| O_LARGEFILE
, 0);
820 xftruncate (outfd
, 0);
828 /* Skip the other sizes unless they have been
840 #include <support/test-driver.c>