2015-07-01 22:23:09 +00:00
|
|
|
/*
|
|
|
|
* CDDL HEADER START
|
|
|
|
*
|
|
|
|
* The contents of this file are subject to the terms of the
|
|
|
|
* Common Development and Distribution License (the "License").
|
|
|
|
* You may not use this file except in compliance with the License.
|
|
|
|
*
|
|
|
|
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
|
2022-07-11 21:16:13 +00:00
|
|
|
* or https://opensource.org/licenses/CDDL-1.0.
|
2015-07-01 22:23:09 +00:00
|
|
|
* See the License for the specific language governing permissions
|
|
|
|
* and limitations under the License.
|
|
|
|
*
|
|
|
|
* When distributing Covered Code, include this CDDL HEADER in each
|
|
|
|
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
|
|
|
|
* If applicable, add the following below this CDDL HEADER, with the
|
|
|
|
* fields enclosed by brackets "[]" replaced with your own identifying
|
|
|
|
* information: Portions Copyright [yyyy] [name of copyright owner]
|
|
|
|
*
|
|
|
|
* CDDL HEADER END
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright 2007 Sun Microsystems, Inc. All rights reserved.
|
|
|
|
* Use is subject to license terms.
|
|
|
|
*/
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Copyright (c) 2013 by Delphix. All rights reserved.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2019-12-18 20:29:43 +00:00
|
|
|
#ifndef __FreeBSD__
|
2017-09-13 19:20:07 +00:00
|
|
|
#include <sys/xattr.h>
|
2019-12-18 20:29:43 +00:00
|
|
|
#endif
|
2015-07-01 22:23:09 +00:00
|
|
|
#include <utime.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <libgen.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#define ST_ATIME 0
|
|
|
|
#define ST_CTIME 1
|
|
|
|
#define ST_MTIME 2
|
|
|
|
|
|
|
|
#define ALL_MODE (mode_t)(S_IRWXU|S_IRWXG|S_IRWXO)
|
|
|
|
|
|
|
|
typedef struct timetest {
|
|
|
|
int type;
|
2022-04-19 18:38:30 +00:00
|
|
|
const char *name;
|
2015-07-01 22:23:09 +00:00
|
|
|
int (*func)(const char *pfile);
|
|
|
|
} timetest_t;
|
|
|
|
|
|
|
|
static char tfile[BUFSIZ] = { 0 };
|
|
|
|
|
|
|
|
/*
|
|
|
|
* DESCRIPTION:
|
|
|
|
* Verify time will be changed correctly after each operation.
|
|
|
|
*
|
|
|
|
* STRATEGY:
|
|
|
|
* 1. Define time test array.
|
|
|
|
* 2. Loop through each item in this array.
|
|
|
|
* 3. Verify the time is changed after each operation.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
static int
|
|
|
|
get_file_time(const char *pfile, int what, time_t *ptr)
|
|
|
|
{
|
|
|
|
struct stat stat_buf;
|
|
|
|
|
|
|
|
if (pfile == NULL || ptr == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (stat(pfile, &stat_buf) == -1) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
switch (what) {
|
|
|
|
case ST_ATIME:
|
|
|
|
*ptr = stat_buf.st_atime;
|
|
|
|
return (0);
|
|
|
|
case ST_CTIME:
|
|
|
|
*ptr = stat_buf.st_ctime;
|
|
|
|
return (0);
|
|
|
|
case ST_MTIME:
|
|
|
|
*ptr = stat_buf.st_mtime;
|
|
|
|
return (0);
|
|
|
|
default:
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-10-07 17:31:26 +00:00
|
|
|
static ssize_t
|
|
|
|
get_dirnamelen(const char *path)
|
|
|
|
{
|
|
|
|
const char *end = strrchr(path, '/');
|
|
|
|
return (end ? end - path : -1);
|
|
|
|
}
|
|
|
|
|
2015-07-01 22:23:09 +00:00
|
|
|
static int
|
|
|
|
do_read(const char *pfile)
|
|
|
|
{
|
|
|
|
int fd, ret = 0;
|
|
|
|
char buf[BUFSIZ] = { 0 };
|
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = open(pfile, O_RDONLY, ALL_MODE)) == -1) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (read(fd, buf, sizeof (buf)) == -1) {
|
|
|
|
(void) fprintf(stderr, "read(%d, buf, %zd) failed with errno "
|
|
|
|
"%d\n", fd, sizeof (buf), errno);
|
2016-09-21 00:45:45 +00:00
|
|
|
(void) close(fd);
|
2015-07-01 22:23:09 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_write(const char *pfile)
|
|
|
|
{
|
|
|
|
int fd, ret = 0;
|
|
|
|
char buf[BUFSIZ] = "call function do_write()";
|
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = open(pfile, O_WRONLY, ALL_MODE)) == -1) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
if (write(fd, buf, strlen(buf)) == -1) {
|
|
|
|
(void) fprintf(stderr, "write(%d, buf, %d) failed with errno "
|
|
|
|
"%d\n", fd, (int)strlen(buf), errno);
|
2016-09-21 00:45:45 +00:00
|
|
|
(void) close(fd);
|
2015-07-01 22:23:09 +00:00
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_link(const char *pfile)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2021-05-22 15:19:14 +00:00
|
|
|
char link_file[BUFSIZ + 16] = { 0 };
|
2015-07-01 22:23:09 +00:00
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Figure out source file directory name, and create
|
|
|
|
* the link file in the same directory.
|
|
|
|
*/
|
2021-05-22 15:19:14 +00:00
|
|
|
(void) snprintf(link_file, sizeof (link_file),
|
2021-10-07 17:31:26 +00:00
|
|
|
"%.*s/%s", (int)get_dirnamelen(pfile), pfile, "link_file");
|
2015-07-01 22:23:09 +00:00
|
|
|
|
|
|
|
if (link(pfile, link_file) == -1) {
|
|
|
|
(void) fprintf(stderr, "link(%s, %s) failed with errno %d\n",
|
|
|
|
pfile, link_file, errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
(void) unlink(link_file);
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_creat(const char *pfile)
|
|
|
|
{
|
|
|
|
int fd, ret = 0;
|
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((fd = creat(pfile, ALL_MODE)) == -1) {
|
|
|
|
(void) fprintf(stderr, "creat(%s, ALL_MODE) failed with errno "
|
|
|
|
"%d\n", pfile, errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_utime(const char *pfile)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Times of the file are set to the current time
|
|
|
|
*/
|
|
|
|
if (utime(pfile, NULL) == -1) {
|
|
|
|
(void) fprintf(stderr, "utime(%s, NULL) failed with errno "
|
|
|
|
"%d\n", pfile, errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_chmod(const char *pfile)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chmod(pfile, ALL_MODE) == -1) {
|
|
|
|
(void) fprintf(stderr, "chmod(%s, ALL_MODE) failed with "
|
|
|
|
"errno %d\n", pfile, errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
do_chown(const char *pfile)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (chown(pfile, getuid(), getgid()) == -1) {
|
|
|
|
(void) fprintf(stderr, "chown(%s, %d, %d) failed with errno "
|
|
|
|
"%d\n", pfile, (int)getuid(), (int)getgid(), errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
return (ret);
|
|
|
|
}
|
|
|
|
|
2019-12-18 20:29:43 +00:00
|
|
|
#ifndef __FreeBSD__
|
2017-09-13 19:20:07 +00:00
|
|
|
static int
|
|
|
|
do_xattr(const char *pfile)
|
|
|
|
{
|
|
|
|
int ret = 0;
|
2022-04-19 18:38:30 +00:00
|
|
|
const char *value = "user.value";
|
2017-09-13 19:20:07 +00:00
|
|
|
|
|
|
|
if (pfile == NULL) {
|
|
|
|
return (-1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (setxattr(pfile, "user.x", value, strlen(value), 0) == -1) {
|
|
|
|
(void) fprintf(stderr, "setxattr(%s, %d, %d) failed with errno "
|
|
|
|
"%d\n", pfile, (int)getuid(), (int)getgid(), errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
return (ret);
|
|
|
|
}
|
2019-12-18 20:29:43 +00:00
|
|
|
#endif
|
2017-09-13 19:20:07 +00:00
|
|
|
|
2015-07-01 22:23:09 +00:00
|
|
|
static void
|
|
|
|
cleanup(void)
|
|
|
|
{
|
|
|
|
if ((strlen(tfile) != 0) && (access(tfile, F_OK) == 0)) {
|
|
|
|
(void) unlink(tfile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static timetest_t timetest_table[] = {
|
|
|
|
{ ST_ATIME, "st_atime", do_read },
|
|
|
|
{ ST_ATIME, "st_atime", do_utime },
|
|
|
|
{ ST_MTIME, "st_mtime", do_creat },
|
|
|
|
{ ST_MTIME, "st_mtime", do_write },
|
|
|
|
{ ST_MTIME, "st_mtime", do_utime },
|
|
|
|
{ ST_CTIME, "st_ctime", do_creat },
|
|
|
|
{ ST_CTIME, "st_ctime", do_write },
|
|
|
|
{ ST_CTIME, "st_ctime", do_chmod },
|
|
|
|
{ ST_CTIME, "st_ctime", do_chown },
|
|
|
|
{ ST_CTIME, "st_ctime", do_link },
|
|
|
|
{ ST_CTIME, "st_ctime", do_utime },
|
2019-12-18 20:29:43 +00:00
|
|
|
#ifndef __FreeBSD__
|
2017-09-13 19:20:07 +00:00
|
|
|
{ ST_CTIME, "st_ctime", do_xattr },
|
2019-12-18 20:29:43 +00:00
|
|
|
#endif
|
2015-07-01 22:23:09 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
#define NCOMMAND (sizeof (timetest_table) / sizeof (timetest_table[0]))
|
|
|
|
|
|
|
|
int
|
2021-12-11 01:24:35 +00:00
|
|
|
main(void)
|
2015-07-01 22:23:09 +00:00
|
|
|
{
|
|
|
|
int i, ret, fd;
|
2022-04-19 18:38:30 +00:00
|
|
|
const char *penv[] = {"TESTDIR", "TESTFILE0"};
|
2015-07-01 22:23:09 +00:00
|
|
|
|
|
|
|
(void) atexit(cleanup);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get the environment variable values.
|
|
|
|
*/
|
|
|
|
for (i = 0; i < sizeof (penv) / sizeof (char *); i++) {
|
|
|
|
if ((penv[i] = getenv(penv[i])) == NULL) {
|
|
|
|
(void) fprintf(stderr, "getenv(penv[%d])\n", i);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
(void) snprintf(tfile, sizeof (tfile), "%s/%s", penv[0], penv[1]);
|
|
|
|
|
|
|
|
/*
|
2021-05-22 15:19:14 +00:00
|
|
|
* If the test file exists, remove it first.
|
2015-07-01 22:23:09 +00:00
|
|
|
*/
|
|
|
|
if (access(tfile, F_OK) == 0) {
|
|
|
|
(void) unlink(tfile);
|
|
|
|
}
|
|
|
|
ret = 0;
|
|
|
|
if ((fd = open(tfile, O_WRONLY | O_CREAT | O_TRUNC, ALL_MODE)) == -1) {
|
|
|
|
(void) fprintf(stderr, "open(%s) failed: %d\n", tfile, errno);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
(void) close(fd);
|
|
|
|
|
|
|
|
for (i = 0; i < NCOMMAND; i++) {
|
|
|
|
time_t t1, t2;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get original time before operating.
|
|
|
|
*/
|
|
|
|
ret = get_file_time(tfile, timetest_table[i].type, &t1);
|
|
|
|
if (ret != 0) {
|
|
|
|
(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
|
|
|
|
tfile, timetest_table[i].type, ret);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Sleep 2 seconds, then invoke command on given file
|
|
|
|
*/
|
|
|
|
(void) sleep(2);
|
|
|
|
timetest_table[i].func(tfile);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Get time after operating.
|
|
|
|
*/
|
|
|
|
ret = get_file_time(tfile, timetest_table[i].type, &t2);
|
|
|
|
if (ret != 0) {
|
|
|
|
(void) fprintf(stderr, "get_file_time(%s %d) = %d\n",
|
|
|
|
tfile, timetest_table[i].type, ret);
|
|
|
|
return (1);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (t1 == t2) {
|
|
|
|
(void) fprintf(stderr, "%s: t1(%ld) == t2(%ld)\n",
|
|
|
|
timetest_table[i].name, (long)t1, (long)t2);
|
|
|
|
return (1);
|
|
|
|
} else {
|
|
|
|
(void) fprintf(stderr, "%s: t1(%ld) != t2(%ld)\n",
|
|
|
|
timetest_table[i].name, (long)t1, (long)t2);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return (0);
|
|
|
|
}
|