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
do_prepare(int argc,char ** argv)40 do_prepare (int argc, char **argv)
41 {
42   temp_fd = create_temp_file ("tst-preadvwritev.", &temp_filename);
43   if (temp_fd == -1)
44     FAIL_EXIT1 ("cannot create temporary file");
45   temp_fd_supports_holes = support_descriptor_supports_holes (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
do_test_without_offset(void)60 do_test_without_offset (void)
61 {
62   xftruncate (temp_fd, 0);
63 
64   xwrite (temp_fd, "123", 3);
65   xlseek (temp_fd, 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 (temp_fd, 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 (temp_fd, 0);
93 }
94 
95 static int
do_test_with_offset(off_t offset)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