1 /* Tests for copy_file_range.
2 Copyright (C) 2017-2023 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 <https://www.gnu.org/licenses/>. */
19 #include <array_length.h>
27 #include <support/check.h>
28 #include <support/support.h>
29 #include <support/temp_file.h>
30 #include <support/test-driver.h>
31 #include <support/xunistd.h>
33 /* Boolean flags which indicate whether to use pointers with explicit
38 /* Name and descriptors of the input files. Files are truncated and
39 reopened (with O_RDWR) between tests. */
45 /* Input and output offsets. Set according to do_inoff and do_outoff
46 before the test. The offsets themselves are always set to
49 static off64_t
*pinoff
;
50 static off64_t outoff
;
51 static off64_t
*poutoff
;
53 /* These are a collection of copy sizes used in tests. */
54 enum { maximum_size
= 99999 };
55 static const int typical_sizes
[] =
56 { 0, 1, 2, 3, 1024, 2048, 4096, 8191, 8192, 8193, maximum_size
};
58 /* The random contents of this array can be used as a pattern to check
59 for correct write operations. */
60 static unsigned char random_data
[maximum_size
];
62 /* The size chosen by the test harness. */
63 static int current_size
;
65 /* Perform a copy of a file. */
67 simple_file_copy (void)
69 xwrite (infd
, random_data
, current_size
);
72 int in_skipped
; /* Expected skipped bytes in input. */
75 xlseek (infd
, 1, SEEK_SET
);
77 length
= current_size
- 3;
82 xlseek (infd
, 3, SEEK_SET
);
83 length
= current_size
- 5;
86 int out_skipped
; /* Expected skipped bytes before the written data. */
89 xlseek (outfd
, 4, SEEK_SET
);
95 xlseek (outfd
, 6, SEEK_SET
);
96 length
= current_size
- 6;
102 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
106 TEST_COMPARE (inoff
, 2 + length
);
107 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 1);
110 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 3 + length
);
113 TEST_COMPARE (outoff
, 5 + length
);
114 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 4);
117 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 6 + length
);
122 TEST_COMPARE (st
.st_size
, out_skipped
+ length
);
125 /* If we did not write anything, we also did not add any
127 TEST_COMPARE (st
.st_size
, 0);
131 xlseek (outfd
, 0, SEEK_SET
);
132 char *bytes
= xmalloc (st
.st_size
);
133 TEST_COMPARE (read (outfd
, bytes
, st
.st_size
), st
.st_size
);
134 for (int i
= 0; i
< out_skipped
; ++i
)
135 TEST_COMPARE (bytes
[i
], 0);
136 TEST_VERIFY (memcmp (bytes
+ out_skipped
, random_data
+ in_skipped
,
141 /* Test that a short input file results in a shortened copy. */
145 if (current_size
== 0)
146 /* Nothing to shorten. */
149 /* Two subtests, one with offset 0 and current_size - 1 bytes, and
150 another one with current_size bytes, but offset 1. */
151 for (int shift
= 0; shift
< 2; ++shift
)
153 if (test_verbose
> 0)
154 printf ("info: shift=%d\n", shift
);
155 xftruncate (infd
, 0);
156 xlseek (infd
, 0, SEEK_SET
);
157 xwrite (infd
, random_data
, current_size
- !shift
);
162 xlseek (infd
, 2, SEEK_SET
);
167 xlseek (infd
, shift
, SEEK_SET
);
169 xftruncate (outfd
, 0);
170 xlseek (outfd
, 0, SEEK_SET
);
173 /* First call copies current_size - 1 bytes. */
174 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
175 current_size
, 0), current_size
- 1);
176 char *buffer
= xmalloc (current_size
);
177 TEST_COMPARE (pread64 (outfd
, buffer
, current_size
, 0),
179 TEST_VERIFY (memcmp (buffer
, random_data
+ shift
, current_size
- 1)
185 TEST_COMPARE (inoff
, current_size
- 1 + shift
);
186 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 2);
189 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), current_size
- 1 + shift
);
192 TEST_COMPARE (outoff
, current_size
- 1);
193 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
196 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), current_size
- 1);
198 /* First call copies zero bytes. */
199 TEST_COMPARE (copy_file_range (infd
, pinoff
, outfd
, poutoff
,
200 current_size
, 0), 0);
201 /* And the offsets are unchanged. */
204 TEST_COMPARE (inoff
, current_size
- 1 + shift
);
205 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), 2);
208 TEST_COMPARE (xlseek (infd
, 0, SEEK_CUR
), current_size
- 1 + shift
);
211 TEST_COMPARE (outoff
, current_size
- 1);
212 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), 0);
215 TEST_COMPARE (xlseek (outfd
, 0, SEEK_CUR
), current_size
- 1);
219 /* A named test function. */
224 bool sizes
; /* If true, call the test with different current_size values. */
227 /* The available test cases. */
228 static struct test_case tests
[] =
230 { "simple_file_copy", simple_file_copy
, .sizes
= true },
231 { "short_copy", short_copy
, .sizes
= true },
237 for (unsigned char *p
= random_data
; p
< array_end (random_data
); ++p
)
240 infd
= create_temp_file ("tst-copy_file_range-in-", &infile
);
241 outfd
= create_temp_file ("tst-copy_file_range-out-", &outfile
);
243 ssize_t ret
= copy_file_range (infd
, NULL
, outfd
, NULL
, 0, 0);
247 FAIL_UNSUPPORTED ("copy_file_range is not support on this system");
248 FAIL_EXIT1 ("copy_file_range probing call: %m");
254 for (do_inoff
= 0; do_inoff
< 2; ++do_inoff
)
255 for (do_outoff
= 0; do_outoff
< 2; ++do_outoff
)
256 for (struct test_case
*test
= tests
; test
< array_end (tests
); ++test
)
257 for (const int *size
= typical_sizes
;
258 size
< array_end (typical_sizes
); ++size
)
260 current_size
= *size
;
261 if (test_verbose
> 0)
262 printf ("info: %s do_inoff=%d do_outoff=%d current_size=%d\n",
263 test
->name
, do_inoff
, do_outoff
, current_size
);
276 infd
= xopen (infile
, O_RDWR
| O_LARGEFILE
, 0);
277 xftruncate (infd
, 0);
278 outfd
= xopen (outfile
, O_RDWR
| O_LARGEFILE
, 0);
279 xftruncate (outfd
, 0);
287 /* Skip the other sizes unless they have been
298 #include <support/test-driver.c>