]> git.proxmox.com Git - mirror_zfs.git/blame - tests/zfs-tests/cmd/ctime.c
Linux 6.7 compat: zfs_setattr fix atime update
[mirror_zfs.git] / tests / zfs-tests / cmd / ctime.c
CommitLineData
6bb24f4d
BB
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
7 *
8 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
1d3ba0bf 9 * or https://opensource.org/licenses/CDDL-1.0.
6bb24f4d
BB
10 * See the License for the specific language governing permissions
11 * and limitations under the License.
12 *
13 * When distributing Covered Code, include this CDDL HEADER in each
14 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15 * If applicable, add the following below this CDDL HEADER, with the
16 * fields enclosed by brackets "[]" replaced with your own identifying
17 * information: Portions Copyright [yyyy] [name of copyright owner]
18 *
19 * CDDL HEADER END
20 */
21
22/*
23 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 */
26
27/*
28 * Copyright (c) 2013 by Delphix. All rights reserved.
29 */
30
31
32#include <sys/types.h>
33#include <sys/stat.h>
7839c4b5 34#ifndef __FreeBSD__
0107f698 35#include <sys/xattr.h>
7839c4b5 36#endif
6bb24f4d
BB
37#include <utime.h>
38#include <stdio.h>
39#include <stdlib.h>
40#include <unistd.h>
6bb24f4d
BB
41#include <errno.h>
42#include <fcntl.h>
43#include <libgen.h>
44#include <string.h>
45
46#define ST_ATIME 0
47#define ST_CTIME 1
48#define ST_MTIME 2
49
50#define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
51
52typedef struct timetest {
53 int type;
a926aab9 54 const char *name;
6bb24f4d
BB
55 int (*func)(const char *pfile);
56} timetest_t;
57
58static char tfile[BUFSIZ] = { 0 };
59
60/*
61 * DESCRIPTION:
62 * Verify time will be changed correctly after each operation.
63 *
64 * STRATEGY:
65 * 1. Define time test array.
66 * 2. Loop through each item in this array.
67 * 3. Verify the time is changed after each operation.
68 *
69 */
70
71static int
72get_file_time(const char *pfile, int what, time_t *ptr)
73{
74 struct stat stat_buf;
75
76 if (pfile == NULL || ptr == NULL) {
77 return (-1);
78 }
79
80 if (stat(pfile, &stat_buf) == -1) {
81 return (-1);
82 }
83
84 switch (what) {
85 case ST_ATIME:
86 *ptr = stat_buf.st_atime;
87 return (0);
88 case ST_CTIME:
89 *ptr = stat_buf.st_ctime;
90 return (0);
91 case ST_MTIME:
92 *ptr = stat_buf.st_mtime;
93 return (0);
94 default:
95 return (-1);
96 }
97}
98
514498fe
BB
99static ssize_t
100get_dirnamelen(const char *path)
101{
102 const char *end = strrchr(path, '/');
103 return (end ? end - path : -1);
104}
105
6bb24f4d
BB
106static int
107do_read(const char *pfile)
108{
109 int fd, ret = 0;
110 char buf[BUFSIZ] = { 0 };
111
112 if (pfile == NULL) {
113 return (-1);
114 }
115
116 if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
117 return (-1);
118 }
119 if (read(fd, buf, sizeof (buf)) == -1) {
120 (void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "
121 "%d\n", fd, sizeof (buf), errno);
884385a0 122 (void) close(fd);
6bb24f4d
BB
123 return (1);
124 }
125 (void) close(fd);
126
127 return (ret);
128}
129
130static int
131do_write(const char *pfile)
132{
133 int fd, ret = 0;
134 char buf[BUFSIZ] = "call function do_write()";
135
136 if (pfile == NULL) {
137 return (-1);
138 }
139
140 if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
141 return (-1);
142 }
143 if (write(fd, buf, strlen(buf)) == -1) {
144 (void) fprintf(stderr, "write(%d, buf, %d) failed with errno "
145 "%d\n", fd, (int)strlen(buf), errno);
884385a0 146 (void) close(fd);
6bb24f4d
BB
147 return (1);
148 }
149 (void) close(fd);
150
151 return (ret);
152}
153
154static int
155do_link(const char *pfile)
156{
157 int ret = 0;
feb04e66 158 char link_file[BUFSIZ + 16] = { 0 };
6bb24f4d
BB
159
160 if (pfile == NULL) {
161 return (-1);
162 }
163
164 /*
165 * Figure out source file directory name, and create
166 * the link file in the same directory.
167 */
feb04e66 168 (void) snprintf(link_file, sizeof (link_file),
514498fe 169 "%.*s/%s", (int)get_dirnamelen(pfile), pfile, "link_file");
6bb24f4d
BB
170
171 if (link(pfile, link_file) == -1) {
172 (void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",
173 pfile, link_file, errno);
174 return (1);
175 }
176
177 (void) unlink(link_file);
178
179 return (ret);
180}
181
182static int
183do_creat(const char *pfile)
184{
185 int fd, ret = 0;
186
187 if (pfile == NULL) {
188 return (-1);
189 }
190
191 if ((fd = creat(pfile, ALL_MODE)) == -1) {
192 (void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
193 "%d\n", pfile, errno);
194 return (1);
195 }
196 (void) close(fd);
197
198 return (ret);
199}
200
201static int
202do_utime(const char *pfile)
203{
204 int ret = 0;
205
206 if (pfile == NULL) {
207 return (-1);
208 }
209
210 /*
211 * Times of the file are set to the current time
212 */
213 if (utime(pfile, NULL) == -1) {
214 (void) fprintf(stderr, "utime(%s, NULL) failed with errno "
215 "%d\n", pfile, errno);
216 return (1);
217 }
218
219 return (ret);
220}
221
222static int
223do_chmod(const char *pfile)
224{
225 int ret = 0;
226
227 if (pfile == NULL) {
228 return (-1);
229 }
230
231 if (chmod(pfile, ALL_MODE) == -1) {
232 (void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
233 "errno %d\n", pfile, errno);
234 return (1);
235 }
236
237 return (ret);
238}
239
240static int
241do_chown(const char *pfile)
242{
243 int ret = 0;
244
245 if (pfile == NULL) {
246 return (-1);
247 }
248
249 if (chown(pfile, getuid(), getgid()) == -1) {
250 (void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "
251 "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
252 return (1);
253 }
254
255 return (ret);
256}
257
7839c4b5 258#ifndef __FreeBSD__
0107f698
GK
259static int
260do_xattr(const char *pfile)
261{
262 int ret = 0;
a926aab9 263 const char *value = "user.value";
0107f698
GK
264
265 if (pfile == NULL) {
266 return (-1);
267 }
268
269 if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) {
270 (void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno "
271 "%d\n", pfile, (int)getuid(), (int)getgid(), errno);
272 return (1);
273 }
274 return (ret);
275}
7839c4b5 276#endif
0107f698 277
6bb24f4d
BB
278static void
279cleanup(void)
280{
281 if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {
282 (void) unlink(tfile);
283 }
284}
285
286static timetest_t timetest_table[] = {
287 { ST_ATIME, "st_atime", do_read },
288 { ST_ATIME, "st_atime", do_utime },
289 { ST_MTIME, "st_mtime", do_creat },
290 { ST_MTIME, "st_mtime", do_write },
291 { ST_MTIME, "st_mtime", do_utime },
292 { ST_CTIME, "st_ctime", do_creat },
293 { ST_CTIME, "st_ctime", do_write },
294 { ST_CTIME, "st_ctime", do_chmod },
295 { ST_CTIME, "st_ctime", do_chown },
296 { ST_CTIME, "st_ctime", do_link },
297 { ST_CTIME, "st_ctime", do_utime },
7839c4b5 298#ifndef __FreeBSD__
0107f698 299 { ST_CTIME, "st_ctime", do_xattr },
7839c4b5 300#endif
6bb24f4d
BB
301};
302
303#define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
304
6bb24f4d 305int
cf8d708b 306main(void)
6bb24f4d
BB
307{
308 int i, ret, fd;
a926aab9 309 const char *penv[] = {"TESTDIR", "TESTFILE0"};
6bb24f4d 310
6bb24f4d
BB
311 (void) atexit(cleanup);
312
313 /*
314 * Get the environment variable values.
315 */
316 for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
317 if ((penv[i] = getenv(penv[i])) == NULL) {
318 (void) fprintf(stderr, "getenv(penv[%d])\n", i);
319 return (1);
320 }
321 }
322 (void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);
323
324 /*
feb04e66 325 * If the test file exists, remove it first.
6bb24f4d
BB
326 */
327 if (access(tfile, F_OK) == 0) {
328 (void) unlink(tfile);
329 }
6bb24f4d
BB
330 if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {
331 (void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);
332 return (1);
333 }
334 (void) close(fd);
335
336 for (i = 0; i < NCOMMAND; i++) {
337 time_t t1, t2;
338
339 /*
340 * Get original time before operating.
341 */
342 ret = get_file_time(tfile, timetest_table[i].type, &t1);
343 if (ret != 0) {
344 (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
345 tfile, timetest_table[i].type, ret);
346 return (1);
347 }
348
349 /*
350 * Sleep 2 seconds, then invoke command on given file
351 */
352 (void) sleep(2);
353 timetest_table[i].func(tfile);
354
355 /*
356 * Get time after operating.
357 */
358 ret = get_file_time(tfile, timetest_table[i].type, &t2);
359 if (ret != 0) {
360 (void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
361 tfile, timetest_table[i].type, ret);
362 return (1);
363 }
364
f0bf7a24
RN
365
366 /*
367 * Ideally, time change would be exactly two seconds, but allow
368 * a little slack in case of scheduling delays or similar.
369 */
370 long delta = (long)t2 - (long)t1;
371 if (delta < 2 || delta > 4) {
372 (void) fprintf(stderr,
373 "%s: BAD time change: t1(%ld), t2(%ld)\n",
6bb24f4d
BB
374 timetest_table[i].name, (long)t1, (long)t2);
375 return (1);
376 } else {
f0bf7a24
RN
377 (void) fprintf(stderr,
378 "%s: good time change: t1(%ld), t2(%ld)\n",
6bb24f4d
BB
379 timetest_table[i].name, (long)t1, (long)t2);
380 }
381 }
382
6bb24f4d
BB
383 return (0);
384}