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>
36 #include <sys/mount.h>
38 /* Boolean flags which indicate whether to use pointers with explicit
43 /* Name and descriptors of the input files. Files are truncated and
44 reopened (with O_RDWR) between tests. */
50 /* Like the above, but on a different file system. xdevfile can be
51 NULL if no suitable file system has been found. */
52 static char *xdevfile
;
54 /* Input and output offsets. Set according to do_inoff and do_outoff
55 before the test. The offsets themselves are always set to
58 static off64_t
*pinoff
;
59 static off64_t outoff
;
60 static off64_t
*poutoff
;
62 /* These are a collection of copy sizes used in tests. The selection
63 takes into account that the fallback implementation uses an
64 internal buffer of 8192 bytes. */
65 enum { maximum_size
= 99999 };
66 static const int typical_sizes
[] =
67 { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, 16383, 16384, 16385,
70 /* The random contents of this array can be used as a pattern to check
71 for correct write operations. */
72 static unsigned char random_data
[maximum_size
];
74 /* The size chosen by the test harness. */
75 static int current_size
;
77 /* Maximum writable file offset. Updated by find_maximum_offset
79 static off64_t maximum_offset
;
81 /* Error code when crossing the offset. */
82 static int maximum_offset_errno
;
84 /* If true: Writes which cross the limit will fail. If false: Writes
85 which cross the limit will result in a partial write. */
86 static bool maximum_offset_hard_limit
;
88 /* Fills maximum_offset etc. above. Truncates outfd as a side
91 find_maximum_offset (void)
93 xftruncate (outfd
, 0);
94 if (maximum_offset
!= 0)
98 upper
>>= 1; /* Maximum of off64_t. */
99 TEST_VERIFY ((off64_t
) upper
> 0);
100 TEST_VERIFY ((off64_t
) (upper
+ 1) < 0);
101 if (lseek64 (outfd
, upper
, SEEK_SET
) >= 0)
103 if (write (outfd
, "", 1) == 1)
104 FAIL_EXIT1 ("created a file larger than the off64_t range");
107 uint64_t lower
= 1024 * 1024; /* A reasonable minimum file size. */
108 /* Loop invariant: writing at lower succeeds, writing at upper fails. */
109 while (lower
+ 1 < upper
)
111 uint64_t middle
= (lower
+ upper
) / 2;
112 if (test_verbose
> 0)
113 printf ("info: %s: remaining test range %" PRIu64
" .. %" PRIu64
114 ", probe at %" PRIu64
"\n", __func__
, lower
, upper
, middle
);
115 xftruncate (outfd
, 0);
116 if (lseek64 (outfd
, middle
, SEEK_SET
) >= 0
117 && write (outfd
, "", 1) == 1)
122 TEST_VERIFY (lower
+ 1 == upper
);
123 maximum_offset
= lower
;
124 printf ("info: maximum writable file offset: %" PRIu64
" (%" PRIx64
")\n",
127 /* Check that writing at the valid offset actually works. */
128 xftruncate (outfd
, 0);
129 xlseek (outfd
, lower
, SEEK_SET
);
130 TEST_COMPARE (write (outfd
, "", 1), 1);
132 /* Cross the boundary with a two-byte write. This can either result
133 in a short write, or a failure. */
134 xlseek (outfd
, lower
, SEEK_SET
);
135 ssize_t ret
= write (outfd
, " ", 2);
138 maximum_offset_errno
= errno
;
139 maximum_offset_hard_limit
= true;
142 maximum_offset_hard_limit
= false;
144 /* Check that writing at the next offset actually fails. This also
145 obtains the expected errno value. */
146 xftruncate (outfd
, 0);
148 if (lseek64 (outfd
, lower
+ 1, SEEK_SET
) != 0)
150 if (write (outfd
, "", 1) != -1)
151 FAIL_EXIT1 ("write to impossible offset %" PRIu64
" succeeded",
154 int errno_copy
= errno
;
155 if (maximum_offset_hard_limit
)
156 TEST_COMPARE (errno_copy
, maximum_offset_errno
);
158 maximum_offset_errno
= errno_copy
;
163 maximum_offset_errno
= errno
;
165 printf ("info: %s out of range fails with %m (%d)\n",
166 action
, maximum_offset_errno
);
168 xftruncate (outfd
, 0);
169 xlseek (outfd
, 0, SEEK_SET
);
172 /* Perform a copy of a file. */
174 simple_file_copy (void)
176 xwrite (infd
, random_data
, current_size
);
179 int in_skipped
; /* Expected skipped bytes in input. */
182 xlseek (infd
, 1, SEEK_SET
);
184 length
= current_size
- 3;
189 xlseek (infd
, 3, SEEK_SET
);
190 length
= current_size
- 5;
193 int out_skipped
; /* Expected skipped bytes before the written data. */
196 xlseek (outfd
, 4, SEEK_SET
);
202 xlseek (outfd
, 6, SEEK_SET
);
203 length
= current_size
- 6;
209 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
213 TEST_COMPARE (inoff
, 2 + length
);
214 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 1);
217 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 3 + length
);
220 TEST_COMPARE (outoff
, 5 + length
);
221 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 4);
224 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 6 + length
);
229 TEST_COMPARE (st
.st_size
, out_skipped
+ length
);
232 /* If we did not write anything, we also did not add any
234 TEST_COMPARE (st
.st_size
, 0);
238 xlseek (outfd
, 0, SEEK_SET
);
239 char *bytes
= xmalloc (st
.st_size
);
240 TEST_COMPARE (read (outfd
, bytes
, st
.st_size
), st
.st_size
);
241 for (int i
= 0; i
< out_skipped
; ++i
)
242 TEST_COMPARE (bytes
[i
], 0);
243 TEST_VERIFY (memcmp (bytes
+ out_skipped
, random_data
+ in_skipped
,
248 /* Test that reading from a pipe willfails. */
250 pipe_as_source (void)
255 for (int length
= 0; length
< 2; ++length
)
257 if (test_verbose
> 0)
258 printf ("info: %s: length=%d\n", __func__
, length
);
260 /* Make sure that there is something to copy in the pipe. */
261 xwrite (pipefds
[1], "@", 1);
263 TEST_COMPARE (copy_file_range (pipefds
[0], pinoff
, outfd
, poutoff
,
265 /* Linux 4.10 and later return EINVAL. Older kernels return
267 TEST_VERIFY (errno
== EINVAL
|| errno
== EXDEV
);
268 TEST_COMPARE (inoff
, 0);
269 TEST_COMPARE (outoff
, 0);
270 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
272 /* Make sure that nothing was read. */
274 TEST_COMPARE (read (pipefds
[0], &buf
, 1), 1);
275 TEST_COMPARE (buf
, '@');
282 /* Test that writing to a pipe fails. */
284 pipe_as_destination (void)
286 /* Make sure that there is something to read in the input file. */
287 xwrite (infd
, "abc", 3);
288 xlseek (infd
, 0, SEEK_SET
);
293 for (int length
= 0; length
< 2; ++length
)
295 if (test_verbose
> 0)
296 printf ("info: %s: length=%d\n", __func__
, length
);
298 TEST_COMPARE (copy_file_range (infd
, pinoff
, pipefds
[1], poutoff
,
300 /* Linux 4.10 and later return EINVAL. Older kernels return
302 TEST_VERIFY (errno
== EINVAL
|| errno
== EXDEV
);
303 TEST_COMPARE (inoff
, 0);
304 TEST_COMPARE (outoff
, 0);
305 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
307 /* Make sure that nothing was written. */
308 struct pollfd pollfd
= { .fd
= pipefds
[0], .events
= POLLIN
, };
309 TEST_COMPARE (poll (&pollfd
, 1, 0), 0);
316 /* Test a write failure after (potentially) writing some bytes.
317 Failure occurs near the start of the buffer. */
319 delayed_write_failure_beginning (void)
321 /* We need to write something to provoke the error. */
322 if (current_size
== 0)
324 xwrite (infd
, random_data
, sizeof (random_data
));
325 xlseek (infd
, 0, SEEK_SET
);
327 /* Write failure near the start. The actual error code varies among
329 find_maximum_offset ();
330 off64_t where
= maximum_offset
;
332 if (current_size
== 1)
336 xlseek (outfd
, 1, SEEK_SET
);
338 xlseek (outfd
, where
, SEEK_SET
);
339 if (maximum_offset_hard_limit
|| where
> maximum_offset
)
341 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
342 sizeof (random_data
), 0), -1);
343 TEST_COMPARE (errno
, maximum_offset_errno
);
344 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
345 TEST_COMPARE (inoff
, 0);
347 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 1);
349 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), where
);
350 TEST_COMPARE (outoff
, where
);
353 TEST_COMPARE (st
.st_size
, 0);
357 /* The offset is not a hard limit. This means we write one
359 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
360 sizeof (random_data
), 0), 1);
363 TEST_COMPARE (inoff
, 1);
364 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
368 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 1);
369 TEST_COMPARE (inoff
, 0);
373 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 1);
374 TEST_COMPARE (outoff
, where
+ 1);
378 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), where
+ 1);
379 TEST_COMPARE (outoff
, where
);
383 TEST_COMPARE (st
.st_size
, where
+ 1);
387 /* Test a write failure after (potentially) writing some bytes.
388 Failure occurs near the end of the buffer. */
390 delayed_write_failure_end (void)
392 if (current_size
<= 1)
393 /* This would be same as the first test because there is not
394 enough data to write to make a difference. */
396 xwrite (infd
, random_data
, sizeof (random_data
));
397 xlseek (infd
, 0, SEEK_SET
);
399 find_maximum_offset ();
400 off64_t where
= maximum_offset
- current_size
+ 1;
401 if (current_size
== sizeof (random_data
))
402 /* Otherwise we do not reach the non-writable byte. */
406 xlseek (outfd
, 1, SEEK_SET
);
408 xlseek (outfd
, where
, SEEK_SET
);
409 ssize_t ret
= copy_file_range (infd
, pinoff
, outfd
, poutoff
,
410 sizeof (random_data
), 0);
413 TEST_COMPARE (ret
, -1);
414 TEST_COMPARE (errno
, maximum_offset_errno
);
417 TEST_COMPARE (st
.st_size
, 0);
421 /* The first copy succeeded. This happens in the emulation
422 because the internal buffer of limited size does not
423 necessarily cross the off64_t boundary on the first write
425 if (test_verbose
> 0)
426 printf ("info: copy_file_range (%zu) returned %zd\n",
427 sizeof (random_data
), ret
);
428 TEST_VERIFY (ret
> 0);
429 TEST_VERIFY (ret
< maximum_size
);
432 TEST_COMPARE (st
.st_size
, where
+ ret
);
435 TEST_COMPARE (inoff
, ret
);
436 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
439 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), ret
);
441 char *buffer
= xmalloc (ret
);
442 TEST_COMPARE (pread64 (outfd
, buffer
, ret
, where
), ret
);
443 TEST_VERIFY (memcmp (buffer
, random_data
, ret
) == 0);
446 /* The second copy fails. */
447 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
448 sizeof (random_data
), 0), -1);
449 TEST_COMPARE (errno
, maximum_offset_errno
);
453 /* Test a write failure across devices. */
455 cross_device_failure (void)
457 if (xdevfile
== NULL
)
458 /* Subtest not supported due to missing cross-device file. */
461 /* We need something to write. */
462 xwrite (infd
, random_data
, sizeof (random_data
));
463 xlseek (infd
, 0, SEEK_SET
);
465 int xdevfd
= xopen (xdevfile
, O_RDWR
| O_LARGEFILE
, 0);
466 TEST_COMPARE (copy_file_range (infd
, pinoff
, xdevfd
, poutoff
,
467 current_size
, 0), -1);
468 TEST_COMPARE (errno
, EXDEV
);
469 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 0);
471 xfstat (xdevfd
, &st
);
472 TEST_COMPARE (st
.st_size
, 0);
477 /* Try to exercise ENOSPC behavior with a tempfs file system (so that
478 we do not have to fill up a regular file system to get the error).
479 This function runs in a subprocess, so that we do not change the
480 mount namespace of the actual test process. */
482 enospc_failure_1 (void *closure
)
485 support_become_root ();
487 /* Make sure that we do not alter the file system mounts of the
489 if (! support_enter_mount_namespace ())
491 printf ("warning: ENOSPC test skipped\n");
495 char *mountpoint
= closure
;
496 if (mount ("none", mountpoint
, "tmpfs", MS_NODEV
| MS_NOEXEC
,
499 printf ("warning: could not mount tmpfs at %s: %m\n", mountpoint
);
503 /* The source file must reside on the same file system. */
504 char *intmpfsfile
= xasprintf ("%s/%s", mountpoint
, "in");
505 int intmpfsfd
= xopen (intmpfsfile
, O_RDWR
| O_CREAT
| O_LARGEFILE
, 0600);
506 xwrite (intmpfsfd
, random_data
, sizeof (random_data
));
507 xlseek (intmpfsfd
, 1, SEEK_SET
);
510 char *outtmpfsfile
= xasprintf ("%s/%s", mountpoint
, "out");
511 int outtmpfsfd
= xopen (outtmpfsfile
, O_RDWR
| O_CREAT
| O_LARGEFILE
, 0600);
513 /* Fill the file with data until ENOSPC is reached. */
516 ssize_t ret
= write (outtmpfsfd
, random_data
, sizeof (random_data
));
517 if (ret
< 0 && errno
!= ENOSPC
)
518 FAIL_EXIT1 ("write to %s: %m", outtmpfsfile
);
519 if (ret
< sizeof (random_data
))
522 TEST_COMPARE (write (outtmpfsfd
, "", 1), -1);
523 TEST_COMPARE (errno
, ENOSPC
);
524 off64_t maxsize
= xlseek (outtmpfsfd
, 0, SEEK_CUR
);
525 TEST_VERIFY_EXIT (maxsize
> sizeof (random_data
));
527 /* Constructed the expected file contents. */
528 char *expected
= xmalloc (maxsize
);
529 TEST_COMPARE (pread64 (outtmpfsfd
, expected
, maxsize
, 0), maxsize
);
530 /* Go back a little, so some bytes can be written. */
531 enum { offset
= 20000 };
532 TEST_VERIFY_EXIT (offset
< maxsize
);
533 TEST_VERIFY_EXIT (offset
< sizeof (random_data
));
534 memcpy (expected
+ maxsize
- offset
, random_data
+ 1, offset
);
538 outoff
= maxsize
- offset
;
539 xlseek (outtmpfsfd
, 2, SEEK_SET
);
542 xlseek (outtmpfsfd
, -offset
, SEEK_CUR
);
544 /* First call is expected to succeed because we made room for some
546 TEST_COMPARE (copy_file_range (intmpfsfd
, pinoff
, outtmpfsfd
, poutoff
,
547 maximum_size
, 0), offset
);
550 TEST_COMPARE (inoff
, 1 + offset
);
551 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1);
554 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1 + offset
);
557 TEST_COMPARE (outoff
, maxsize
);
558 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), 2);
561 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), maxsize
);
563 xfstat (outtmpfsfd
, &st
);
564 TEST_COMPARE (st
.st_size
, maxsize
);
565 char *actual
= xmalloc (st
.st_size
);
566 TEST_COMPARE (pread64 (outtmpfsfd
, actual
, st
.st_size
, 0), st
.st_size
);
567 TEST_VERIFY (memcmp (expected
, actual
, maxsize
) == 0);
569 /* Second call should fail with ENOSPC. */
570 TEST_COMPARE (copy_file_range (intmpfsfd
, pinoff
, outtmpfsfd
, poutoff
,
571 maximum_size
, 0), -1);
572 TEST_COMPARE (errno
, ENOSPC
);
574 /* Offsets should be unchanged. */
577 TEST_COMPARE (inoff
, 1 + offset
);
578 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1);
581 TEST_COMPARE (xlseek (intmpfsfd
, 0, SEEK_CUR
), 1 + offset
);
584 TEST_COMPARE (outoff
, maxsize
);
585 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), 2);
588 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_CUR
), maxsize
);
589 TEST_COMPARE (xlseek (outtmpfsfd
, 0, SEEK_END
), maxsize
);
590 TEST_COMPARE (pread64 (outtmpfsfd
, actual
, maxsize
, 0), maxsize
);
591 TEST_VERIFY (memcmp (expected
, actual
, maxsize
) == 0);
601 #else /* !CLONE_NEWNS */
602 puts ("warning: ENOSPC test skipped (no mount namespaces)");
606 /* Call enospc_failure_1 in a subprocess. */
608 enospc_failure (void)
611 = support_create_temp_directory ("tst-copy_file_range-enospc-");
612 support_isolate_in_subprocess (enospc_failure_1
, mountpoint
);
616 /* The target file descriptor must have O_APPEND enabled. */
618 oappend_failure (void)
620 /* Add data, to make sure we do not fail because there is
621 insufficient input data. */
622 xwrite (infd
, random_data
, current_size
);
623 xlseek (infd
, 0, SEEK_SET
);
626 outfd
= xopen (outfile
, O_RDWR
| O_APPEND
, 0);
627 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
628 current_size
, 0), -1);
629 TEST_COMPARE (errno
, EBADF
);
632 /* Test that a short input file results in a shortened copy. */
636 if (current_size
== 0)
637 /* Nothing to shorten. */
640 /* Two subtests, one with offset 0 and current_size - 1 bytes, and
641 another one with current_size bytes, but offset 1. */
642 for (int shift
= 0; shift
< 2; ++shift
)
644 if (test_verbose
> 0)
645 printf ("info: shift=%d\n", shift
);
646 xftruncate (infd
, 0);
647 xlseek (infd
, 0, SEEK_SET
);
648 xwrite (infd
, random_data
, current_size
- !shift
);
653 xlseek (infd
, 2, SEEK_SET
);
658 xlseek (infd
, shift
, SEEK_SET
);
660 ftruncate (outfd
, 0);
661 xlseek (outfd
, 0, SEEK_SET
);
664 /* First call copies current_size - 1 bytes. */
665 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
666 current_size
, 0), current_size
- 1);
667 char *buffer
= xmalloc (current_size
);
668 TEST_COMPARE (pread64 (outfd
, buffer
, current_size
, 0),
670 TEST_VERIFY (memcmp (buffer
, random_data
+ shift
, current_size
- 1)
676 TEST_COMPARE (inoff
, current_size
- 1 + shift
);
677 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 2);
680 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), current_size
- 1 + shift
);
683 TEST_COMPARE (outoff
, current_size
- 1);
684 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
687 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), current_size
- 1);
689 /* First call copies zero bytes. */
690 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
691 current_size
, 0), 0);
692 /* And the offsets are unchanged. */
695 TEST_COMPARE (inoff
, current_size
- 1 + shift
);
696 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 2);
699 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), current_size
- 1 + shift
);
702 TEST_COMPARE (outoff
, current_size
- 1);
703 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
706 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), current_size
- 1);
710 /* A named test function. */
715 bool sizes
; /* If true, call the test with different current_size values. */
718 /* The available test cases. */
719 static struct test_case tests
[] =
721 { "simple_file_copy", simple_file_copy
, .sizes
= true },
722 { "pipe_as_source", pipe_as_source
, },
723 { "pipe_as_destination", pipe_as_destination
, },
724 { "delayed_write_failure_beginning", delayed_write_failure_beginning
,
726 { "delayed_write_failure_end", delayed_write_failure_end
, .sizes
= true },
727 { "cross_device_failure", cross_device_failure
, .sizes
= true },
728 { "enospc_failure", enospc_failure
, },
729 { "oappend_failure", oappend_failure
, .sizes
= true },
730 { "short_copy", short_copy
, .sizes
= true },
736 for (unsigned char *p
= random_data
; p
< array_end (random_data
); ++p
)
739 infd
= create_temp_file ("tst-copy_file_range-in-", &infile
);
740 xclose (create_temp_file ("tst-copy_file_range-out-", &outfile
));
742 /* Try to find a different directory from the default input/output
745 struct stat64 instat
;
746 xfstat (infd
, &instat
);
747 static const char *const candidates
[] =
748 { NULL
, "/var/tmp", "/dev/shm" };
749 for (const char *const *c
= candidates
; c
< array_end (candidates
); ++c
)
751 const char *path
= *c
;
752 char *to_free
= NULL
;
755 to_free
= xreadlink ("/proc/self/exe");
756 path
= dirname (to_free
);
760 xstat (path
, &cstat
);
761 if (cstat
.st_dev
== instat
.st_dev
)
767 printf ("info: using alternate temporary files directory: %s\n", path
);
768 xdevfile
= xasprintf ("%s/tst-copy_file_range-xdev-XXXXXX", path
);
772 if (xdevfile
!= NULL
)
774 int xdevfd
= mkstemp (xdevfile
);
776 FAIL_EXIT1 ("mkstemp (\"%s\"): %m", xdevfile
);
777 struct stat64 xdevst
;
778 xfstat (xdevfd
, &xdevst
);
779 TEST_VERIFY (xdevst
.st_dev
!= instat
.st_dev
);
780 add_temp_file (xdevfile
);
784 puts ("warning: no alternate directory on different file system found");
788 for (do_inoff
= 0; do_inoff
< 2; ++do_inoff
)
789 for (do_outoff
= 0; do_outoff
< 2; ++do_outoff
)
790 for (struct test_case
*test
= tests
; test
< array_end (tests
); ++test
)
791 for (const int *size
= typical_sizes
;
792 size
< array_end (typical_sizes
); ++size
)
794 current_size
= *size
;
795 if (test_verbose
> 0)
796 printf ("info: %s do_inoff=%d do_outoff=%d current_size=%d\n",
797 test
->name
, do_inoff
, do_outoff
, current_size
);
810 infd
= xopen (infile
, O_RDWR
| O_LARGEFILE
, 0);
811 xftruncate (infd
, 0);
812 outfd
= xopen (outfile
, O_RDWR
| O_LARGEFILE
, 0);
813 xftruncate (outfd
, 0);
821 /* Skip the other sizes unless they have been
833 #include <support/test-driver.c>