mirror of
https://github.com/sudo-project/sudo.git
synced 2025-08-31 06:15:37 +00:00
Use futimens() and utimensat() instead of futimes() and utimes().
This commit is contained in:
198
lib/util/utimens.c
Normal file
198
lib/util/utimens.c
Normal file
@@ -0,0 +1,198 @@
|
||||
/*
|
||||
* Copyright (c) 2015 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#if !defined(HAVE_FUTIMENS) || !defined(HAVE_UTIMENSAT)
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
#include <stdio.h>
|
||||
#include <errno.h>
|
||||
#ifdef TIME_WITH_SYS_TIME
|
||||
# include <time.h>
|
||||
#endif
|
||||
#ifndef HAVE_STRUCT_TIMESPEC
|
||||
# include "compat/timespec.h"
|
||||
#endif
|
||||
#ifdef HAVE_UTIME_H
|
||||
# include <utime.h>
|
||||
#else
|
||||
# include "compat/utime.h"
|
||||
#endif
|
||||
|
||||
#include "sudo_compat.h"
|
||||
|
||||
#if !defined(HAVE_FUTIMES) && defined(HAVE_FUTIMESAT)
|
||||
# define futimes(_f, _tv) futimesat(_f, NULL, _tv)
|
||||
# define HAVE_FUTIMES
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_ST_MTIM)
|
||||
# ifdef HAVE_ST__TIM
|
||||
# define ATIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_atim.st__tim)
|
||||
# define MTIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_mtim.st__tim)
|
||||
# else
|
||||
# define ATIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_atim)
|
||||
# define MTIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_mtim)
|
||||
# endif
|
||||
#elif defined(HAVE_ST_MTIMESPEC)
|
||||
# define ATIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_atimespec)
|
||||
# define MTIME_TO_TIMEVAL(_x, _y) TIMESPEC_TO_TIMEVAL((_x), &(_y)->st_mtimespec)
|
||||
#else
|
||||
# define ATIME_TO_TIMEVAL(_x, _y) do { (_x)->tv_sec = (_y)->st_atime; (_x)->tv_usec = 0; } while (0)
|
||||
# define MTIME_TO_TIMEVAL(_x, _y) do { (_x)->tv_sec = (_y)->st_mtime; (_x)->tv_usec = 0; } while (0)
|
||||
#endif /* HAVE_ST_MTIM */
|
||||
|
||||
/*
|
||||
* Convert the pair of timespec structs passed to futimens() / utimensat()
|
||||
* to a pair of timeval structs, handling UTIME_OMIT and UTIME_NOW.
|
||||
* Returns 0 on success and -1 on failure (setting errno).
|
||||
*/
|
||||
static int
|
||||
utimens_ts_to_tv(int fd, const char *file, const struct timespec *ts,
|
||||
struct timeval *tv)
|
||||
{
|
||||
TIMESPEC_TO_TIMEVAL(&tv[0], &ts[0]);
|
||||
TIMESPEC_TO_TIMEVAL(&tv[1], &ts[1]);
|
||||
if (ts[0].tv_nsec == UTIME_OMIT || ts[1].tv_nsec == UTIME_OMIT) {
|
||||
struct stat sb;
|
||||
|
||||
if (fd != -1) {
|
||||
/* For futimens() */
|
||||
if (fstat(fd, &sb) == -1)
|
||||
return -1;
|
||||
} else {
|
||||
/* For utimensat() */
|
||||
if (stat(file, &sb) == -1)
|
||||
return -1;
|
||||
}
|
||||
if (ts[0].tv_nsec == UTIME_OMIT)
|
||||
ATIME_TO_TIMEVAL(&tv[0], &sb);
|
||||
if (ts[1].tv_nsec == UTIME_OMIT)
|
||||
MTIME_TO_TIMEVAL(&tv[1], &sb);
|
||||
}
|
||||
if (ts[0].tv_nsec == UTIME_NOW || ts[1].tv_nsec == UTIME_NOW) {
|
||||
struct timeval now;
|
||||
|
||||
if (gettimeofday(&now, NULL) == -1)
|
||||
return -1;
|
||||
if (ts[0].tv_nsec == UTIME_NOW)
|
||||
tv[0] = now;
|
||||
if (ts[1].tv_nsec == UTIME_NOW)
|
||||
tv[1] = now;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(HAVE_FUTIMES)
|
||||
/*
|
||||
* Emulate futimens() via futimes()
|
||||
*/
|
||||
int
|
||||
sudo_futimens(int fd, const struct timespec *ts)
|
||||
{
|
||||
struct timeval tv[2], *times = NULL;
|
||||
|
||||
if (ts != NULL) {
|
||||
if (utimens_ts_to_tv(fd, NULL, ts, tv) == -1)
|
||||
return -1;
|
||||
times = tv;
|
||||
}
|
||||
return futimes(fd, times);
|
||||
}
|
||||
#elif defined(HAVE_FUTIME)
|
||||
/*
|
||||
* Emulate futimens() via futime()
|
||||
*/
|
||||
int
|
||||
sudo_futimens(int fd, const struct timeval *ts)
|
||||
{
|
||||
struct utimbuf utb, *times = NULL;
|
||||
|
||||
if (ts != NULL) {
|
||||
struct timeval tv[2];
|
||||
|
||||
if (utimens_ts_to_tv(fd, NULL, ts, tv) == -1)
|
||||
return -1;
|
||||
utb.actime = (time_t)(tv[0].tv_sec + tv[0].tv_usec / 1000000);
|
||||
utb.modtime = (time_t)(tv[1].tv_sec + tv[1].tv_usec / 1000000);
|
||||
times = &utb;
|
||||
}
|
||||
return futime(fd, times);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Nothing to do but fail.
|
||||
*/
|
||||
int
|
||||
sudo_futimens(int fd, const struct timeval *ts)
|
||||
{
|
||||
errno = ENOSYS;
|
||||
return -1;
|
||||
}
|
||||
#endif /* HAVE_FUTIMES */
|
||||
|
||||
#if defined(HAVE_UTIMES)
|
||||
/*
|
||||
* Emulate utimensat() via utimes()
|
||||
*/
|
||||
int
|
||||
sudo_utimensat(int fd, const char *file, const struct timespec *ts, int flag)
|
||||
{
|
||||
struct timeval tv[2], *times = NULL;
|
||||
|
||||
if (fd != AT_FDCWD || flag != 0) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ts != NULL) {
|
||||
if (utimens_ts_to_tv(-1, file, ts, tv) == -1)
|
||||
return -1;
|
||||
times = tv;
|
||||
}
|
||||
return utimes(file, times);
|
||||
}
|
||||
#else
|
||||
/*
|
||||
* Emulate utimensat() via utime()
|
||||
*/
|
||||
int
|
||||
sudo_utimensat(int fd, const char *file, const struct timespec *ts, int flag)
|
||||
{
|
||||
struct utimbuf utb, *times = NULL;
|
||||
|
||||
if (fd != AT_FDCWD || flag != 0) {
|
||||
errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (ts != NULL) {
|
||||
struct timeval tv[2];
|
||||
|
||||
if (utimens_ts_to_tv(-1, file, ts, tv) == -1)
|
||||
return -1;
|
||||
utb.actime = (time_t)(tv[0].tv_sec + tv[0].tv_usec / 1000000);
|
||||
utb.modtime = (time_t)(tv[1].tv_sec + tv[1].tv_usec / 1000000);
|
||||
times = &utb;
|
||||
}
|
||||
return utime(file, times);
|
||||
}
|
||||
#endif /* !HAVE_UTIMES */
|
||||
|
||||
#endif /* !HAVE_FUTIMENS && !HAVE_UTIMENSAT */
|
Reference in New Issue
Block a user