1 /*
2  * Copyright (C) 2024 HiHope Open Source Organization.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <cerrno>
17 #include <cstdio>
18 #include <cstdlib>
19 #include <string>
20 #include <vector>
21 #include <fcntl.h>
22 #include <unistd.h>
23 #include <arpa/inet.h>
24 #include <gtest/gtest.h>
25 #include <netinet/in.h>
26 #include <sys/stat.h>
27 #include <sys/socket.h>
28 #include <sys/types.h>
29 #include "securec.h"
30 
31 using namespace testing::ext;
32 
33 static const char *TEST_READ_FILE = "/data/local/tmp/splice_read_file.txt";
34 static const char *TEST_WRITE_FILE = "/data/local/tmp/splice_write_file.txt";
35 static const char *TEST_DATA = "Hello World!";
36 static const int TEST_DATA_LEN = strlen(TEST_DATA);
37 static const int MAX_LEN = 128;
38 
39 class HatsSpliceTest : public testing::Test {
40 public:
41 static void SetUpTestCase();
42 static void TearDownTestCase();
43 void SetUp();
44 void TearDown();
45 private:
46 };
SetUp()47 void HatsSpliceTest::SetUp()
48 {
49     int fd = open(TEST_READ_FILE, O_WRONLY | O_CREAT, 0644);
50     write(fd, TEST_DATA, TEST_DATA_LEN);
51     close(fd);
52 }
TearDown()53 void HatsSpliceTest::TearDown()
54 {
55     (void)remove(TEST_READ_FILE);
56     (void)remove(TEST_WRITE_FILE);
57 }
SetUpTestCase()58 void HatsSpliceTest::SetUpTestCase()
59 {
60 }
TearDownTestCase()61 void HatsSpliceTest::TearDownTestCase()
62 {
63 }
64 
65 /*
66  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0100
67  * @tc.name   : SpliceMoveFileDataToPipeSuccess_0001
68  * @tc.desc   : Splice move data from file to pipe success.
69  * @tc.size   : MediumTest
70  * @tc.type   : Function
71  * @tc.level  : Level 1
72  */
HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0001, Function | MediumTest | Level1)73 HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0001, Function | MediumTest | Level1)
74 {
75     int ret;
76     char buffer[MAX_LEN] = { 0 };
77     int pipeFd[2];
78     int fdIn = open(TEST_READ_FILE, O_RDONLY);
79     EXPECT_TRUE(fdIn > 0);
80 
81     // move common fd data to pipe success.
82     ret = pipe(pipeFd);
83     EXPECT_EQ(ret, 0);
84 
85     ssize_t size = splice(fdIn, nullptr, pipeFd[1], nullptr, TEST_DATA_LEN, SPLICE_F_MOVE | SPLICE_F_MORE);
86     EXPECT_EQ(size, TEST_DATA_LEN);
87 
88     size = read(pipeFd[0], buffer, MAX_LEN);
89     EXPECT_EQ(size, TEST_DATA_LEN);
90     EXPECT_STREQ(buffer, TEST_DATA);
91 
92     close(fdIn);
93     close(pipeFd[0]);
94     close(pipeFd[1]);
95 }
96 
97 /*
98  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0200
99  * @tc.name   : SpliceMovePipeDataToFileSuccess_0002
100  * @tc.desc   : Splice move pipe data to file success.
101  * @tc.size   : MediumTest
102  * @tc.type   : Function
103  * @tc.level  : Level 1
104  */
HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0002, Function | MediumTest | Level1)105 HWTEST_F(HatsSpliceTest, SpliceMoveFileDataToPipeSuccess_0002, Function | MediumTest | Level1)
106 {
107     int ret;
108     off64_t offset = 0;
109     char buffer[MAX_LEN] = { 0 };
110     int pipeFd[2];
111     int fdOut = open(TEST_WRITE_FILE, O_RDWR | O_CREAT, 0644);
112     EXPECT_TRUE(fdOut > 0);
113 
114     // move common fd data to pipe success.
115     ret = pipe(pipeFd);
116     EXPECT_EQ(ret, 0);
117     ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
118     EXPECT_EQ(size, TEST_DATA_LEN);
119 
120     ret = splice(pipeFd[0], nullptr, fdOut, &offset, TEST_DATA_LEN, SPLICE_F_MOVE | SPLICE_F_MORE);
121     EXPECT_EQ(ret, TEST_DATA_LEN);
122 
123     off_t pos = lseek(fdOut, 0, SEEK_SET);
124     EXPECT_EQ(pos, 0);
125 
126     size = read(fdOut, buffer, MAX_LEN);
127     EXPECT_EQ(size, TEST_DATA_LEN);
128     EXPECT_STREQ(buffer, TEST_DATA);
129 
130     close(fdOut);
131     close(pipeFd[0]);
132     close(pipeFd[1]);
133 }
134 
135 /*
136  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0300
137  * @tc.name   : SpliceInvalidFdFailed_0003
138  * @tc.desc   : Splice was provided invalid file fd return failed, errno EBADF.
139  * @tc.size   : MediumTest
140  * @tc.type   : Function
141  * @tc.level  : Level 2
142  */
HWTEST_F(HatsSpliceTest, SpliceInvalidFdFailed_0003, Function | MediumTest | Level2)143 HWTEST_F(HatsSpliceTest, SpliceInvalidFdFailed_0003, Function | MediumTest | Level2)
144 {
145     int ret;
146     off64_t offset = 0;
147     int pipeFd[2];
148 
149     ret = pipe(pipeFd);
150     EXPECT_EQ(ret, 0);
151     ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
152     EXPECT_EQ(size, TEST_DATA_LEN);
153 
154     // fdOut is invalid fd, failed
155     errno = 0;
156     ret = splice(pipeFd[0], nullptr, -1, &offset, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
157     EXPECT_EQ(ret, -1);
158     EXPECT_EQ(errno, EBADF);
159 
160     // fdIn is invalid fd, failed
161     errno = 0;
162     ret = splice(-1, &offset, pipeFd[1], nullptr, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
163     EXPECT_EQ(ret, -1);
164     EXPECT_EQ(errno, EBADF);
165 
166     close(pipeFd[0]);
167     close(pipeFd[1]);
168 }
169 
170 /*
171  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0400
172  * @tc.name   : SpliceNoPipeFdFailed_0004
173  * @tc.desc   : Splice neither fds refer to a pipe return failed, errno EINVAL.
174  * @tc.size   : MediumTest
175  * @tc.type   : Function
176  * @tc.level  : Level 2
177  */
HWTEST_F(HatsSpliceTest, SpliceNoPipeFdFailed_0004, Function | MediumTest | Level2)178 HWTEST_F(HatsSpliceTest, SpliceNoPipeFdFailed_0004, Function | MediumTest | Level2)
179 {
180     int ret;
181     off64_t offset = 0;
182     int fdIn = open(TEST_READ_FILE, O_RDONLY);
183     EXPECT_TRUE(fdIn > 0);
184     int fdOut = open(TEST_WRITE_FILE, O_RDWR | O_TRUNC | O_CREAT, 0644);
185     EXPECT_TRUE(fdOut > 0);
186     errno = 0;
187     ret = splice(fdIn, &offset, fdOut, &offset, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
188     EXPECT_EQ(ret, -1);
189     EXPECT_EQ(errno, EINVAL);
190 
191     close(fdIn);
192     close(fdOut);
193 }
194 
195 /*
196  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0500
197  * @tc.name   : SplicePipeOffsetNotNullFailed_0005
198  * @tc.desc   : Splice pipeFd offset is not nullptr return failed, errno ESPIPE.
199  * @tc.size   : MediumTest
200  * @tc.type   : Function
201  * @tc.level  : Level 2
202  */
HWTEST_F(HatsSpliceTest, SplicePipeOffsetNotNullFailed_0005, Function | MediumTest | Level2)203 HWTEST_F(HatsSpliceTest, SplicePipeOffsetNotNullFailed_0005, Function | MediumTest | Level2)
204 {
205     int ret;
206     off64_t offset = 0;
207     int pipeFd[2];
208     int fdIn = open(TEST_READ_FILE, O_RDONLY);
209     EXPECT_TRUE(fdIn > 0);
210 
211     ret = pipe(pipeFd);
212     EXPECT_EQ(ret, 0);
213 
214     errno = 0;
215     ret = splice(fdIn, nullptr, pipeFd[1], &offset, TEST_DATA_LEN, SPLICE_F_MOVE | SPLICE_F_MORE);
216     EXPECT_EQ(ret, -1);
217     EXPECT_EQ(errno, ESPIPE);
218 
219     close(fdIn);
220     close(pipeFd[0]);
221     close(pipeFd[1]);
222 }
223 
224 /*
225  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0600
226  * @tc.name   : SpliceFdOpenAsAppendFailed_0006
227  * @tc.desc   : Splice file fd was opened in append mode failed, errno EINVAL.
228  * @tc.size   : MediumTest
229  * @tc.type   : Function
230  * @tc.level  : Level 2
231  */
HWTEST_F(HatsSpliceTest, SpliceFdOpenAsAppendFailed_0006, Function | MediumTest | Level2)232 HWTEST_F(HatsSpliceTest, SpliceFdOpenAsAppendFailed_0006, Function | MediumTest | Level2)
233 {
234     int ret;
235     int pipeFd[2];
236     off64_t offset = 0;
237 
238     int fd = open(TEST_WRITE_FILE, O_RDWR | O_APPEND | O_CREAT, 0644);
239     EXPECT_TRUE(fd > 0);
240 
241     ret = pipe(pipeFd);
242     EXPECT_EQ(ret, 0);
243     ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
244     EXPECT_EQ(size, TEST_DATA_LEN);
245 
246     errno = 0;
247     ret = splice(pipeFd[0], nullptr, fd, &offset, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
248     EXPECT_EQ(ret, -1);
249     EXPECT_EQ(errno, EINVAL);
250 
251     close(fd);
252     close(pipeFd[0]);
253     close(pipeFd[1]);
254 }
255 
256 /*
257  * @tc.number : SUB_KERNEL_SYSCALL_SPLICE_0700
258  * @tc.name   : SpliceUseTheSamePipeFdFailed_0007
259  * @tc.desc   : Splice fdIn and fdOut from the same pipe failed, errno EINVAL.
260  * @tc.size   : MediumTest
261  * @tc.type   : Function
262  * @tc.level  : Level 2
263  */
HWTEST_F(HatsSpliceTest, SpliceUseTheSamePipeFdFailed_0007, Function | MediumTest | Level2)264 HWTEST_F(HatsSpliceTest, SpliceUseTheSamePipeFdFailed_0007, Function | MediumTest | Level2)
265 {
266     int ret;
267     int pipeFd[2];
268 
269     ret = pipe(pipeFd);
270     EXPECT_EQ(ret, 0);
271     ssize_t size = write(pipeFd[1], TEST_DATA, TEST_DATA_LEN);
272     EXPECT_EQ(size, TEST_DATA_LEN);
273 
274     errno = 0;
275     ret = splice(pipeFd[0], nullptr, pipeFd[1], nullptr, TEST_DATA_LEN, SPLICE_F_NONBLOCK);
276     EXPECT_EQ(ret, -1);
277     EXPECT_EQ(errno, EINVAL);
278 
279     close(pipeFd[0]);
280     close(pipeFd[1]);
281 }