1/*
2 * Copyright (c) 2022 Huawei Device Co., Ltd.
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 <fcntl.h>
17#include <sys/stat.h>
18#include <sys/time.h>
19#include "test.h"
20
21const char *path = "/data";
22
23extern int __futimesat_time64(int, const char *, const struct timeval [2]);
24
25/**
26 * @tc.name      : futimesat_0100
27 * @tc.desc      : Change timestamps of a file relative to a directory file descriptor
28 * @tc.level     : Level 0
29 */
30void futimesat_0100(void)
31{
32    int dir_fd = open(path, O_RDONLY | O_DIRECTORY);
33    if (dir_fd < 0) {
34        t_error("%s open failed\n", __func__);
35    }
36
37    int fd = openat(dir_fd, "test.txt", O_CREAT | O_RDWR | O_EXCL, 0666);
38    if (fd < 0) {
39        t_error("%s openat failed\n", __func__);
40    }
41
42    write(fd, "helloworld", 5);
43
44    struct stat st1;
45    if (fstat(fd, &st1) != 0) {
46        t_error("%s fstat failed\n", __func__);
47    }
48    close(fd);
49
50    struct timeval tv[2];
51    tv[0].tv_sec = st1.st_atime + 1;
52    tv[0].tv_usec = 0;
53    tv[1].tv_sec = st1.st_mtime + 1;
54    tv[1].tv_usec = 0;
55
56    int result = futimesat(dir_fd, "test.txt", tv);
57    if (result != 0) {
58        t_error("%s futimesat failed\n", __func__);
59    }
60
61    struct stat st2;
62    if (fstatat(dir_fd, "test.txt", &st2, 0) != 0) {
63        t_error("%s fstatat failed\n", __func__);
64    }
65
66    if (st2.st_mtime != tv[1].tv_sec) {
67        t_error("%s stat shows different mtime\n", __func__);
68    }
69
70    if (unlinkat(dir_fd, "test.txt", 0) != 0) {
71        t_error("%s unlinkat failed\n", __func__);
72    }
73
74    close(dir_fd);
75}
76
77/**
78 * @tc.name      : futimesat_0200
79 * @tc.desc      : Test the return value of the function when timeval is NULL
80 * @tc.level     : Level 1
81 */
82void futimesat_0200(void)
83{
84    int dir_fd = open(path, O_RDONLY | O_DIRECTORY);
85    if (dir_fd < 0) {
86        t_error("%s open failed\n", __func__);
87    }
88
89    int fd = openat(dir_fd, "test.txt", O_CREAT | O_RDWR | O_EXCL, 0666);
90    if (fd < 0) {
91        t_error("%s openat failed\n", __func__);
92    }
93
94    int result = futimesat(dir_fd, "test.txt", NULL);
95    if (result != 0) {
96        t_error("%s futimesat failed\n", __func__);
97    }
98
99    if (unlinkat(dir_fd, "test.txt", 0) != 0) {
100        t_error("%s unlinkat failed\n", __func__);
101    }
102
103    close(dir_fd);
104}
105
106/**
107 * @tc.name      : futimesat_0300
108 * @tc.desc      : Test the return value of the function when dirfd is invalid
109 * @tc.level     : Level 2
110 */
111void futimesat_0300(void)
112{
113    int result = futimesat(-1, "test.txt", NULL);
114    if (result != -1) {
115        t_error("%s futimesat should be failed\n", __func__);
116    }
117}
118
119/**
120 * @tc.name      : futimesat_0400
121 * @tc.desc      : Test the return value of the function when pathname is invalid
122 * @tc.level     : Level 2
123 */
124void futimesat_0400(void)
125{
126    int result = futimesat(AT_FDCWD, NULL, NULL);
127    if (result != -1) {
128        t_error("%s futimesat should be failed\n", __func__);
129    }
130}
131
132/**
133 * @tc.name      : futimesat_time64_0200
134 * @tc.desc      : Test the return value of the function when timeval is NULL
135 * @tc.level     : Level 1
136 */
137void futimesat_time64_0200(void)
138{
139    int dir_fd = open(path, O_RDONLY | O_DIRECTORY);
140    if (dir_fd < 0) {
141        t_error("%s open failed\n", __func__);
142    }
143
144    int fd = openat(dir_fd, "test.txt", O_CREAT | O_RDWR | O_EXCL, 0666);
145    if (fd < 0) {
146        t_error("%s openat failed\n", __func__);
147    }
148
149    int result = __futimesat_time64(dir_fd, "test.txt", NULL);
150    if (result != 0) {
151        t_error("%s __futimesat_time64 failed\n", __func__);
152    }
153
154    if (unlinkat(dir_fd, "test.txt", 0) != 0) {
155        t_error("%s unlinkat failed\n", __func__);
156    }
157
158    close(dir_fd);
159}
160
161int main(int argc, char *argv[])
162{
163    futimesat_0100();
164    futimesat_0200();
165    futimesat_0300();
166    futimesat_0400();
167    futimesat_time64_0200();
168    return t_status;
169}