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 <cstdlib>
18#include <cstdio>
19#include <string>
20#include <fcntl.h>
21#include <unistd.h>
22#include <gtest/gtest.h>
23#include <sys/stat.h>
24#include <sys/types.h>
25
26using namespace testing::ext;
27using namespace std;
28
29class OpenatApiTest : public testing::Test {
30public:
31    static void SetUpTestCase();
32    static void TearDownTestCase();
33    void SetUp();
34    void TearDown();
35
36private:
37};
38
39static const char *TEST_DIR = "/data/local/tmp/tmp";
40static const char *TEST_FILE = "/data/local/tmp/tmp/test";
41
42void OpenatApiTest::SetUpTestCase()
43{
44}
45
46void OpenatApiTest::TearDownTestCase()
47{
48}
49
50void OpenatApiTest::SetUp()
51{
52    mkdir(TEST_DIR, S_IRWXU | S_IRWXG | S_IRWXO);
53}
54
55void OpenatApiTest::TearDown()
56{
57    rmdir(TEST_DIR);
58}
59
60/*
61 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0100
62 * @tc.name   : OpenatReadOnlySuccess_0001
63 * @tc.desc   : openat with O_RDONLY should open a file for reading only.
64 * @tc.size   : MediumTest
65 * @tc.type   : Function
66 * @tc.level  : Level 1
67 */
68HWTEST_F(OpenatApiTest, OpenatReadOnlySuccess_0001, Function | MediumTest | Level1)
69{
70    int dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
71
72    int fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT, 0644);
73    EXPECT_TRUE(fd >= 0);
74    close(fd);
75
76    fd = openat(dirFd, TEST_FILE, O_RDONLY);
77    EXPECT_TRUE(fd >= 0);
78
79    errno = 0;
80    ssize_t bytesWritten = write(fd, "A", 1);
81    EXPECT_EQ(bytesWritten, -1);
82    EXPECT_EQ(errno, EBADF);
83    close(fd);
84    unlinkat(dirFd, TEST_FILE, 0);
85    close(dirFd);
86}
87
88/*
89 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0200
90 * @tc.name   : OpenatReadWriteSuccess_0002
91 * @tc.desc   : openat with O_RDWR should open a file for reading and writing.
92 * @tc.size   : MediumTest
93 * @tc.type   : Function
94 * @tc.level  : Level 1
95 */
96HWTEST_F(OpenatApiTest, OpenatReadWriteSuccess_0002, Function | MediumTest | Level1)
97{
98    const char *data = "Hello, World!";
99    char readBuf[128];
100    int dirFd = -1;
101    int fd = -1;
102    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
103    EXPECT_TRUE(dirFd >= 0);
104
105    fd = openat(dirFd, TEST_FILE, O_RDWR | O_CREAT, 0644);
106    EXPECT_TRUE(fd >= 0);
107    write(fd, data, strlen(data));
108    lseek(fd, 0, SEEK_SET);
109    read(fd, readBuf, sizeof(readBuf));
110    EXPECT_STREQ(readBuf, data);
111    close(fd);
112    unlinkat(dirFd, TEST_FILE, 0);
113    close(dirFd);
114}
115
116/*
117 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0300
118 * @tc.name   : OpenatAppendSuccess_0003
119 * @tc.desc   : openat with O_APPEND should append to the end of the file.
120 * @tc.size   : MediumTest
121 * @tc.type   : Function
122 * @tc.level  : Level 1
123 */
124HWTEST_F(OpenatApiTest, OpenatAppendSuccess_0003, Function | MediumTest | Level1)
125{
126    char readBuf[256] = {0};
127    const char *data = "Hello, World!";
128    const char *appendData = " More data";
129    int dirFd = -1;
130    int fd = -1;
131
132    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
133
134    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT, 0644);
135    EXPECT_TRUE(fd >= 0);
136    ssize_t bytesWritten = write(fd, data, strlen(data));
137    EXPECT_EQ(bytesWritten, strlen(data));
138
139    close(fd);
140
141    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_APPEND);
142    EXPECT_TRUE(fd >= 0);
143    bytesWritten = write(fd, appendData, strlen(appendData));
144    EXPECT_EQ(bytesWritten, strlen(appendData));
145
146    close(fd);
147
148    fd = openat(dirFd, TEST_FILE, O_RDONLY);
149    EXPECT_TRUE(fd >= 0);
150    ssize_t bytesRead = read(fd, readBuf, sizeof(readBuf) - 1);
151    EXPECT_TRUE(bytesRead > 0);
152
153    readBuf[bytesRead] = '\0';
154    std::string expectedContent(data);
155    expectedContent += appendData;
156    EXPECT_STREQ(readBuf, expectedContent.c_str());
157
158    close(fd);
159    unlinkat(dirFd, TEST_FILE, 0);
160    close(dirFd);
161}
162
163/*
164 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0400
165 * @tc.name   : OpenatNoFollowFailed_0004
166 * @tc.desc   : openat with O_NOFOLLOW should fail if the path is a symbolic link.
167 * @tc.size   : MediumTest
168 * @tc.type   : Function
169 * @tc.level  : Level 2
170 */
171HWTEST_F(OpenatApiTest, OpenatNoFollowFailed_0004, Function | MediumTest | Level2)
172{
173    int dirFd = -1;
174    int fd = -1;
175    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
176
177    errno = 0;
178    symlink("target", TEST_FILE);
179    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT | O_NOFOLLOW);
180    EXPECT_EQ(fd, -1);
181    EXPECT_EQ(errno, ELOOP);
182    close(dirFd);
183}
184
185/*
186 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0500
187 * @tc.name   : OpenatWriteOnlySuccess_0005
188 * @tc.desc   : openat with O_WRONLY should open a file for writing only.
189 * @tc.size   : MediumTest
190 * @tc.type   : Function
191 * @tc.level  : Level 1
192 */
193HWTEST_F(OpenatApiTest, OpenatWriteOnlySuccess_0005, Function | MediumTest | Level1)
194{
195    int dirFd;
196    int fd;
197    char buf;
198    ssize_t bytesRead;
199    ssize_t bytesWritten;
200    const char *data;
201
202
203    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
204    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT, 0644);
205    EXPECT_TRUE(fd >= 0);
206
207    bytesRead = read(fd, &buf, 1);
208    EXPECT_EQ(bytesRead, -1);
209    EXPECT_EQ(errno, EBADF);
210
211    data = "Test data";
212    bytesWritten = write(fd, data, strlen(data));
213    EXPECT_TRUE(bytesWritten == strlen(data));
214
215    close(fd);
216    unlinkat(dirFd, TEST_FILE, 0);
217    close(dirFd);
218}
219
220/*
221 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0600
222 * @tc.name   : OpenatCreateTest_0006
223 * @tc.desc   : openat with O_CREAT.
224 * @tc.size   : MediumTest
225 * @tc.type   : Function
226 * @tc.level  : Level 2
227 */
228HWTEST_F(OpenatApiTest, OpenatCreateTest_0006, Function | MediumTest | Level2)
229{
230    int dirFd = -1;
231    int fd = -1;
232    struct stat buf;
233    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
234
235    fd = openat(dirFd, TEST_FILE, O_WRONLY, 0644);
236    EXPECT_TRUE(fd == -1);
237    stat(TEST_FILE, &buf);
238    EXPECT_EQ(errno, ENOENT);
239    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT, 0644);
240    EXPECT_TRUE(fd >= 0);
241    EXPECT_TRUE(stat(TEST_FILE, &buf) == 0);
242
243    close(fd);
244    unlinkat(dirFd, TEST_FILE, 0);
245    close(dirFd);
246}
247
248/*
249 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0700
250 * @tc.name   : OpenatDirectoryTest_0007
251 * @tc.desc   : openat with O_DIRECTORY.
252 * @tc.size   : MediumTest
253 * @tc.type   : Function
254 * @tc.level  : Level 2
255 */
256HWTEST_F(OpenatApiTest, OpenatDirectoryTest_0007, Function | MediumTest | Level2)
257{
258    int dirFd = -1;
259    int fd = -1;
260    struct stat buf;
261    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
262
263    fd = open(TEST_FILE, O_WRONLY | O_CREAT, 0644);
264    close(fd);
265    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_DIRECTORY, 0644);
266    EXPECT_TRUE(fd == -1);
267    stat(TEST_FILE, &buf);
268    EXPECT_TRUE(S_ISREG(buf.st_mode));
269    unlinkat(dirFd, TEST_FILE, 0);
270
271    mkdir(TEST_FILE, 0644);
272    fd = openat(dirFd, TEST_FILE, O_DIRECTORY, 0644);
273    EXPECT_TRUE(fd >= 0);
274    stat(TEST_FILE, &buf);
275    EXPECT_TRUE(S_ISDIR(buf.st_mode));
276
277    close(fd);
278    rmdir(TEST_FILE);
279    close(dirFd);
280}
281
282/*
283 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0800
284 * @tc.name   : OpenatExclTest_0008
285 * @tc.desc   : openat with O_EXCL to prevent overwriting the content of existing files.
286 * @tc.size   : MediumTest
287 * @tc.type   : Function
288 * @tc.level  : Level 2
289 */
290HWTEST_F(OpenatApiTest, OpenatExclTest_0008, Function | MediumTest | Level2)
291{
292    int dirFd = -1;
293    int fd = -1;
294    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
295
296    EXPECT_TRUE(access(TEST_FILE, F_OK) == -1);
297    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT | O_EXCL, 0644);
298    EXPECT_TRUE(fd >= 0);
299    close(fd);
300    EXPECT_TRUE(access(TEST_FILE, F_OK) == 0);
301
302    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT | O_EXCL, 0644);
303    EXPECT_TRUE(fd == -1);
304    EXPECT_TRUE(access(TEST_FILE, F_OK) == 0);
305
306    unlinkat(dirFd, TEST_FILE, 0);
307    close(dirFd);
308}
309
310/*
311 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_0900
312 * @tc.name   : OpenatNoatimeSuccess_0009
313 * @tc.desc   : openat with O_NOATIME to prevent changing atime but still changing mtime.
314 * @tc.size   : MediumTest
315 * @tc.type   : Function
316 * @tc.level  : Level 1
317 */
318HWTEST_F(OpenatApiTest, OpenatNoatimeSuccess_0009, Function | MediumTest | Level1)
319{
320    int dirFd = -1;
321    int fd = -1;
322    struct stat bufFirst;
323    struct stat bufSecond;
324    dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
325
326    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_CREAT, 0644);
327    EXPECT_TRUE(fd >= 0);
328    close(fd);
329    stat(TEST_FILE, &bufFirst);
330
331    usleep(100);
332    fd = openat(dirFd, TEST_FILE, O_WRONLY | O_NOATIME, 0644);
333    EXPECT_TRUE(fd >= 0);
334    close(fd);
335    stat(TEST_FILE, &bufSecond);
336    EXPECT_TRUE(bufFirst.st_atime == bufSecond.st_atime);
337
338    unlinkat(dirFd, TEST_FILE, 0);
339    close(dirFd);
340}
341
342/*
343 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_1000
344 * @tc.name   : OpenatFlagsTestSuccess_0010
345 * @tc.desc   : openat with some flags.
346 * @tc.size   : MediumTest
347 * @tc.type   : Function
348 * @tc.level  : Level 1
349 */
350HWTEST_F(OpenatApiTest, OpenatFlagsTestSuccess_0010, Function | MediumTest | Level1)
351{
352    int dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
353
354    // O_TRUNC test
355    int fd = openat(dirFd, TEST_FILE, O_RDWR | O_CREAT, 0644);
356    const char *data = "Test data";
357    write(fd, data, strlen(data));
358    close(fd);
359    fd = openat(dirFd, TEST_FILE, O_RDWR | O_TRUNC, 0644);
360    EXPECT_TRUE(fd >= 0);
361    close(fd);
362    unlinkat(dirFd, TEST_FILE, 0);
363
364    // O_ASYNC test
365    fd = openat(dirFd, TEST_FILE, O_RDWR | O_CREAT | O_ASYNC, 0644);
366    EXPECT_TRUE(fd >= 0);
367    close(fd);
368    unlinkat(dirFd, TEST_FILE, 0);
369
370    // O_DIRECT test
371    fd = openat(dirFd, TEST_FILE, O_RDWR | O_CREAT | O_DIRECT, 0644);
372    EXPECT_TRUE(fd >= 0);
373    close(fd);
374    unlinkat(dirFd, TEST_FILE, 0);
375
376    // O_DSYNC test
377    fd = openat(dirFd, TEST_FILE, O_RDWR | O_CREAT | O_DSYNC, 0644);
378    EXPECT_TRUE(fd >= 0);
379    close(fd);
380    unlinkat(dirFd, TEST_FILE, 0);
381
382    // O_SYNC test
383    fd = openat(dirFd, TEST_FILE, O_RDWR | O_CREAT | O_SYNC, 0644);
384    EXPECT_TRUE(fd >= 0);
385    close(fd);
386    unlinkat(dirFd, TEST_FILE, 0);
387
388    close(dirFd);
389}
390
391/*
392 * @tc.number : SUB_KERNEL_SYSCALL_OPENAT_1100
393 * @tc.name   : OpenatFlagsTestSuccess_0011
394 * @tc.desc   : openat O_CLOEXEC/O_LARGEFILE/O_NOCTTY/O_NONBLOCK flags test success.
395 * @tc.size   : MediumTest
396 * @tc.type   : Function
397 * @tc.level  : Level 1
398 */
399HWTEST_F(OpenatApiTest, OpenatO_CLOEXECFlagSuccess_0011, Function | MediumTest | Level1)
400{
401    int dirFd = open(TEST_DIR, O_RDONLY | O_DIRECTORY);
402
403    int fd = openat(dirFd, TEST_FILE, O_RDWR | O_CLOEXEC | O_CREAT, 0755);
404    EXPECT_TRUE(fd >= 0);
405    close(fd);
406    unlinkat(dirFd, TEST_FILE, 0);
407
408    fd = openat(dirFd, TEST_FILE, O_RDWR | O_LARGEFILE | O_CREAT, 0755);
409    EXPECT_TRUE(fd >= 0);
410    close(fd);
411    unlinkat(dirFd, TEST_FILE, 0);
412
413    fd = openat(dirFd, TEST_FILE, O_RDWR | O_NOCTTY | O_CREAT, 0755);
414    EXPECT_TRUE(fd >= 0);
415    close(fd);
416    unlinkat(dirFd, TEST_FILE, 0);
417
418    fd = openat(dirFd, TEST_FILE, O_RDWR | O_NONBLOCK | O_CREAT, 0755);
419    EXPECT_TRUE(fd >= 0);
420    close(fd);
421    unlinkat(dirFd, TEST_FILE, 0);
422
423    close(dirFd);
424}