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