1 | /* Common definitions for preadv and pwritev. |
2 | Copyright (C) 2016-2022 Free Software Foundation, Inc. |
3 | This file is part of the GNU C Library. |
4 | |
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. |
9 | |
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. |
14 | |
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/>. */ |
18 | |
19 | #include <array_length.h> |
20 | #include <stdbool.h> |
21 | #include <stdio.h> |
22 | #include <stdint.h> |
23 | #include <errno.h> |
24 | #include <string.h> |
25 | #include <sys/uio.h> |
26 | #include <sys/stat.h> |
27 | |
28 | #include <support/check.h> |
29 | #include <support/temp_file.h> |
30 | #include <support/support.h> |
31 | #include <support/xunistd.h> |
32 | |
33 | static char *temp_filename; |
34 | static int temp_fd; |
35 | static bool temp_fd_supports_holes; |
36 | |
37 | static int do_test (void); |
38 | |
39 | static void |
40 | do_prepare (int argc, char **argv) |
41 | { |
42 | temp_fd = create_temp_file (base: "tst-preadvwritev." , filename: &temp_filename); |
43 | if (temp_fd == -1) |
44 | FAIL_EXIT1 ("cannot create temporary file" ); |
45 | temp_fd_supports_holes = support_descriptor_supports_holes (fd: temp_fd); |
46 | } |
47 | #define PREPARE do_prepare |
48 | |
49 | #ifndef PREADV |
50 | # define PREADV(__fd, __iov, __iovcnt, __offset) \ |
51 | preadv (__fd, __iov, __iovcnt, __offset) |
52 | #endif |
53 | |
54 | #ifndef PWRITEV |
55 | # define PWRITEV(__fd, __iov, __iovcnt, __offset) \ |
56 | pwritev (__fd, __iov, __iovcnt, __offset) |
57 | #endif |
58 | |
59 | static __attribute__ ((unused)) void |
60 | do_test_without_offset (void) |
61 | { |
62 | xftruncate (fd: temp_fd, length: 0); |
63 | |
64 | xwrite (temp_fd, "123" , 3); |
65 | xlseek (fd: temp_fd, offset: 2, SEEK_SET); |
66 | { |
67 | struct iovec iov[] = |
68 | { |
69 | { (void *) "abc" , 3 }, |
70 | { (void *) "xyzt" , 4 }, |
71 | }; |
72 | TEST_COMPARE (PWRITEV (temp_fd, iov, array_length (iov), -1), 7); |
73 | } |
74 | TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 9); |
75 | |
76 | xlseek (fd: temp_fd, offset: 1, SEEK_SET); |
77 | char buf1[3]; |
78 | char buf2[2]; |
79 | { |
80 | struct iovec iov[] = |
81 | { |
82 | { buf1, sizeof (buf1) }, |
83 | { buf2, sizeof (buf2) }, |
84 | }; |
85 | TEST_COMPARE (PREADV (temp_fd, iov, array_length (iov), -1), |
86 | sizeof (buf1) + sizeof (buf2)); |
87 | TEST_COMPARE (memcmp ("2ab" , buf1, sizeof (buf1)), 0); |
88 | TEST_COMPARE (memcmp ("cx" , buf2, sizeof (buf2)), 0); |
89 | TEST_COMPARE (xlseek (temp_fd, 0, SEEK_CUR), 6); |
90 | } |
91 | |
92 | xftruncate (fd: temp_fd, length: 0); |
93 | } |
94 | |
95 | static int |
96 | do_test_with_offset (off_t offset) |
97 | { |
98 | struct iovec iov[2]; |
99 | ssize_t ret; |
100 | |
101 | char buf1[32]; |
102 | char buf2[64]; |
103 | |
104 | memset (buf1, 0xf0, sizeof buf1); |
105 | memset (buf2, 0x0f, sizeof buf2); |
106 | |
107 | /* Write two buffer with 32 and 64 bytes respectively. */ |
108 | memset (iov, 0, sizeof iov); |
109 | iov[0].iov_base = buf1; |
110 | iov[0].iov_len = sizeof buf1; |
111 | iov[1].iov_base = buf2; |
112 | iov[1].iov_len = sizeof buf2; |
113 | |
114 | ret = PWRITEV (temp_fd, iov, 2, offset); |
115 | if (ret == -1) |
116 | FAIL_RET ("first pwritev returned -1" ); |
117 | if (ret != (sizeof buf1 + sizeof buf2)) |
118 | FAIL_RET ("first pwritev returned an unexpected value" ); |
119 | |
120 | ret = PWRITEV (temp_fd, iov, 2, sizeof buf1 + sizeof buf2 + offset); |
121 | if (ret == -1) |
122 | FAIL_RET ("second pwritev returned -1" ); |
123 | if (ret != (sizeof buf1 + sizeof buf2)) |
124 | FAIL_RET ("second pwritev returned an unexpected value" ); |
125 | |
126 | char buf3[32]; |
127 | char buf4[64]; |
128 | |
129 | memset (buf3, 0x0f, sizeof buf3); |
130 | memset (buf4, 0xf0, sizeof buf4); |
131 | |
132 | iov[0].iov_base = buf3; |
133 | iov[0].iov_len = sizeof buf3; |
134 | iov[1].iov_base = buf4; |
135 | iov[1].iov_len = sizeof buf4; |
136 | |
137 | /* Now read two buffer with 32 and 64 bytes respectively. */ |
138 | ret = PREADV (temp_fd, iov, 2, offset); |
139 | if (ret == -1) |
140 | FAIL_RET ("first preadv returned -1" ); |
141 | if (ret != (sizeof buf3 + sizeof buf4)) |
142 | FAIL_RET ("first preadv returned an unexpected value" ); |
143 | |
144 | if (memcmp (buf1, buf3, sizeof buf1) != 0) |
145 | FAIL_RET ("first buffer from first preadv different than expected" ); |
146 | if (memcmp (buf2, buf4, sizeof buf2) != 0) |
147 | FAIL_RET ("second buffer from first preadv different than expected" ); |
148 | |
149 | ret = PREADV (temp_fd, iov, 2, sizeof buf3 + sizeof buf4 + offset); |
150 | if (ret == -1) |
151 | FAIL_RET ("second preadv returned -1" ); |
152 | if (ret != (sizeof buf3 + sizeof buf4)) |
153 | FAIL_RET ("second preadv returned an unexpected value" ); |
154 | |
155 | /* And compare the buffers read and written to check if there are equal. */ |
156 | if (memcmp (buf1, buf3, sizeof buf1) != 0) |
157 | FAIL_RET ("first buffer from second preadv different than expected" ); |
158 | if (memcmp (buf2, buf4, sizeof buf2) != 0) |
159 | FAIL_RET ("second buffer from second preadv different than expected" ); |
160 | |
161 | return 0; |
162 | } |
163 | |
164 | #include <support/test-driver.c> |
165 | |