Add futimens and utimensat system calls.
The core kernel part is patch file utimes.2008.4.diff from pluknet@FreeBSD.org. I updated the code for API changes, added the manual page and added compatibility code for old kernels. There is also audit and Capsicum support. A new UTIME_* constant might allow setting birthtimes in future. Differential Revision: https://reviews.freebsd.org/D1426 Submitted by: pluknet (partially) Reviewed by: delphij, pluknet, rwatson Relnotes: yes
This commit is contained in:
parent
4743c20fb6
commit
67db24d0f2
@ -29,7 +29,7 @@
|
||||
.\" @(#)symlink.7 8.3 (Berkeley) 3/31/94
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd December 29, 2014
|
||||
.Dd January 23, 2015
|
||||
.Dt SYMLINK 7
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -147,9 +147,10 @@ unless given the
|
||||
.Dv AT_SYMLINK_NOFOLLOW
|
||||
flag:
|
||||
.Xr fchmodat 2 ,
|
||||
.Xr fchownat 2
|
||||
.Xr fchownat 2 ,
|
||||
.Xr fstatat 2
|
||||
and
|
||||
.Xr fstatat 2 .
|
||||
.Xr utimensat 2 .
|
||||
.Pp
|
||||
The owner and group of an existing symbolic link can be changed by
|
||||
means of the
|
||||
|
@ -357,6 +357,10 @@ int __libc_system(const char *);
|
||||
int __libc_tcdrain(int);
|
||||
int __fcntl_compat(int fd, int cmd, ...);
|
||||
|
||||
int __sys_futimens(int fd, const struct timespec *times) __hidden;
|
||||
int __sys_utimensat(int fd, const char *path,
|
||||
const struct timespec *times, int flag) __hidden;
|
||||
|
||||
/* execve() with PATH processing to implement posix_spawnp() */
|
||||
int _execvpe(const char *, char * const *, char * const *);
|
||||
|
||||
|
@ -38,6 +38,10 @@ SRCS+= ${SYSCALL_COMPAT_SRCS}
|
||||
NOASM+= ${SYSCALL_COMPAT_SRCS:S/.c/.o/}
|
||||
.endif
|
||||
|
||||
SRCS+= futimens.c utimensat.c
|
||||
NOASM+= futimens.o utimensat.o
|
||||
PSEUDO+= _futimens.o _utimensat.o
|
||||
|
||||
INTERPOSED = \
|
||||
accept \
|
||||
accept4 \
|
||||
@ -310,6 +314,7 @@ MAN+= sctp_generic_recvmsg.2 \
|
||||
umask.2 \
|
||||
undelete.2 \
|
||||
unlink.2 \
|
||||
utimensat.2 \
|
||||
utimes.2 \
|
||||
utrace.2 \
|
||||
uuidgen.2 \
|
||||
@ -442,6 +447,7 @@ MLINKS+=timer_settime.2 timer_getoverrun.2 \
|
||||
timer_settime.2 timer_gettime.2
|
||||
MLINKS+=truncate.2 ftruncate.2
|
||||
MLINKS+=unlink.2 unlinkat.2
|
||||
MLINKS+=utimensat.2 futimens.2
|
||||
MLINKS+=utimes.2 futimes.2 \
|
||||
utimes.2 futimesat.2 \
|
||||
utimes.2 lutimes.2
|
||||
|
@ -397,7 +397,9 @@ FBSD_1.3 {
|
||||
};
|
||||
|
||||
FBSD_1.4 {
|
||||
futimens;
|
||||
ppoll;
|
||||
utimensat;
|
||||
};
|
||||
|
||||
FBSDprivate_1.0 {
|
||||
|
97
lib/libc/sys/futimens.c
Normal file
97
lib/libc/sys/futimens.c
Normal file
@ -0,0 +1,97 @@
|
||||
/*-
|
||||
* Copyright (c) 2015 Jilles Tjoelker
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "namespace.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include "un-namespace.h"
|
||||
|
||||
#include "libc_private.h"
|
||||
|
||||
int
|
||||
futimens(int fd, const struct timespec times[2])
|
||||
{
|
||||
struct timeval now, tv[2], *tvp;
|
||||
struct stat sb;
|
||||
|
||||
if (__getosreldate() >= 1100056)
|
||||
return (__sys_futimens(fd, times));
|
||||
|
||||
if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
|
||||
times[1].tv_nsec == UTIME_NOW))
|
||||
tvp = NULL;
|
||||
else if (times[0].tv_nsec == UTIME_OMIT &&
|
||||
times[1].tv_nsec == UTIME_OMIT)
|
||||
return (0);
|
||||
else {
|
||||
if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
|
||||
times[0].tv_nsec != UTIME_NOW &&
|
||||
times[0].tv_nsec != UTIME_OMIT) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
|
||||
times[1].tv_nsec != UTIME_NOW &&
|
||||
times[1].tv_nsec != UTIME_OMIT) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
tv[0].tv_sec = times[0].tv_sec;
|
||||
tv[0].tv_usec = times[0].tv_nsec / 1000;
|
||||
tv[1].tv_sec = times[1].tv_sec;
|
||||
tv[1].tv_usec = times[1].tv_nsec / 1000;
|
||||
tvp = tv;
|
||||
if (times[0].tv_nsec == UTIME_OMIT ||
|
||||
times[1].tv_nsec == UTIME_OMIT) {
|
||||
if (_fstat(fd, &sb) == -1)
|
||||
return (-1);
|
||||
if (times[0].tv_nsec == UTIME_OMIT) {
|
||||
tv[0].tv_sec = sb.st_atim.tv_sec;
|
||||
tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||
}
|
||||
if (times[1].tv_nsec == UTIME_OMIT) {
|
||||
tv[1].tv_sec = sb.st_mtim.tv_sec;
|
||||
tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
|
||||
}
|
||||
}
|
||||
if (times[0].tv_nsec == UTIME_NOW ||
|
||||
times[1].tv_nsec == UTIME_NOW) {
|
||||
if (gettimeofday(&now, NULL) == -1)
|
||||
return (-1);
|
||||
if (times[0].tv_nsec == UTIME_NOW)
|
||||
tv[0] = now;
|
||||
if (times[1].tv_nsec == UTIME_NOW)
|
||||
tv[1] = now;
|
||||
}
|
||||
}
|
||||
return (futimes(fd, tvp));
|
||||
}
|
292
lib/libc/sys/utimensat.2
Normal file
292
lib/libc/sys/utimensat.2
Normal file
@ -0,0 +1,292 @@
|
||||
.\" $NetBSD: utimes.2,v 1.13 1999/03/22 19:45:11 garbled Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1990, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
.\" Copyright (c) 2012, Jilles Tjoelker
|
||||
.\"
|
||||
.\" Redistribution and use in source and binary forms, with or without
|
||||
.\" modification, are permitted provided that the following conditions
|
||||
.\" are met:
|
||||
.\" 1. Redistributions of source code must retain the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer.
|
||||
.\" 2. Redistributions in binary form must reproduce the above copyright
|
||||
.\" notice, this list of conditions and the following disclaimer in the
|
||||
.\" documentation and/or other materials provided with the distribution.
|
||||
.\" 4. Neither the name of the University nor the names of its contributors
|
||||
.\" may be used to endorse or promote products derived from this software
|
||||
.\" without specific prior written permission.
|
||||
.\"
|
||||
.\" THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
|
||||
.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
.\" ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
|
||||
.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
.\" SUCH DAMAGE.
|
||||
.\"
|
||||
.\" @(#)utimes.2 8.1 (Berkeley) 6/4/93
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd January 23, 2015
|
||||
.Dt UTIMENSAT 2
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm futimens ,
|
||||
.Nm utimensat
|
||||
.Nd set file access and modification times
|
||||
.Sh LIBRARY
|
||||
.Lb libc
|
||||
.Sh SYNOPSIS
|
||||
.In sys/stat.h
|
||||
.Ft int
|
||||
.Fn futimens "int fd" "const struct timespec times[2]"
|
||||
.Ft int
|
||||
.Fo utimensat
|
||||
.Fa "int fd"
|
||||
.Fa "const char *path"
|
||||
.Fa "const struct timespec times[2]"
|
||||
.Fa "int flag"
|
||||
.Fc
|
||||
.Sh DESCRIPTION
|
||||
The access and modification times of the file named by
|
||||
.Fa path
|
||||
or referenced by
|
||||
.Fa fd
|
||||
are changed as specified by the argument
|
||||
.Fa times .
|
||||
The inode-change-time of the file is set to the current time.
|
||||
.Pp
|
||||
If
|
||||
.Fa path
|
||||
specifies a relative path,
|
||||
it is relative to the current working directory if
|
||||
.Fa fd
|
||||
is
|
||||
.Dv AT_FDCWD
|
||||
and otherwise relative to the directory associated with the file descriptor
|
||||
.Fa fd .
|
||||
.Pp
|
||||
The
|
||||
.Va tv_nsec
|
||||
field of a
|
||||
.Vt timespec
|
||||
structure
|
||||
can be set to the special value
|
||||
.Dv UTIME_NOW
|
||||
to set the current time, or to
|
||||
.Dv UTIME_OMIT
|
||||
to leave the time unchanged.
|
||||
In either case, the
|
||||
.Va tv_sec
|
||||
field is ignored.
|
||||
.Pp
|
||||
If
|
||||
.Fa times
|
||||
is
|
||||
.No non- Ns Dv NULL ,
|
||||
it is assumed to point to an array of two timespec structures.
|
||||
The access time is set to the value of the first element, and the
|
||||
modification time is set to the value of the second element.
|
||||
For file systems that support file birth (creation) times (such as
|
||||
.Dv UFS2 ) ,
|
||||
the birth time will be set to the value of the second element
|
||||
if the second element is older than the currently set birth time.
|
||||
To set both a birth time and a modification time,
|
||||
two calls are required; the first to set the birth time
|
||||
and the second to set the (presumably newer) modification time.
|
||||
Ideally a new system call will be added that allows the setting
|
||||
of all three times at once.
|
||||
If
|
||||
.Fa times
|
||||
is
|
||||
.Dv NULL ,
|
||||
this is equivalent to passing
|
||||
a pointer to an array of two timespec structures
|
||||
with both
|
||||
.Va tv_nsec
|
||||
fields set to
|
||||
.Dv UTIME_NOW .
|
||||
.Pp
|
||||
If both
|
||||
.Va tv_nsec
|
||||
fields are
|
||||
.Dv UTIME_OMIT ,
|
||||
the timestamps remain unchanged and
|
||||
no permissions are needed for the file itself,
|
||||
although search permissions may be required for the path prefix.
|
||||
The call may or may not succeed if the named file does not exist.
|
||||
.Pp
|
||||
If both
|
||||
.Va tv_nsec
|
||||
fields are
|
||||
.Dv UTIME_NOW ,
|
||||
the caller must be the owner of the file, have permission to
|
||||
write the file, or be the super-user.
|
||||
.Pp
|
||||
For all other values of the timestamps,
|
||||
the caller must be the owner of the file or be the super-user.
|
||||
.Pp
|
||||
The values for the
|
||||
.Fa flag
|
||||
argument of the
|
||||
.Fn utimensat
|
||||
system call
|
||||
are constructed by a bitwise-inclusive OR of flags from the following list,
|
||||
defined in
|
||||
.In fcntl.h :
|
||||
.Bl -tag -width indent
|
||||
.It Dv AT_SYMLINK_NOFOLLOW
|
||||
If
|
||||
.Fa path
|
||||
names a symbolic link, the symbolic link's times are changed.
|
||||
By default,
|
||||
.Fn utimensat
|
||||
changes the times of the file referenced by the symbolic link.
|
||||
.El
|
||||
.Sh RETURN VALUES
|
||||
.Rv -std
|
||||
.Sh COMPATIBILITY
|
||||
If the running kernel does not support this system call,
|
||||
a wrapper emulates it using
|
||||
.Xr fstatat 2 ,
|
||||
.Xr futimesat 2
|
||||
and
|
||||
.Xr lutimes 2 .
|
||||
As a result, timestamps will be rounded down to the nearest microsecond,
|
||||
.Dv UTIME_OMIT
|
||||
is not atomic and
|
||||
.Dv AT_SYMLINK_NOFOLLOW
|
||||
is not available with a path relative to a file descriptor.
|
||||
.Sh ERRORS
|
||||
These system calls will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EACCES
|
||||
The
|
||||
.Fa times
|
||||
argument is
|
||||
.Dv NULL ,
|
||||
or both
|
||||
.Va tv_nsec
|
||||
values are
|
||||
.Dv UTIME_NOW ,
|
||||
and the effective user ID of the process does not
|
||||
match the owner of the file, and is not the super-user, and write
|
||||
access is denied.
|
||||
.It Bq Er EFAULT
|
||||
The
|
||||
.Fa times
|
||||
argument
|
||||
points outside the process's allocated address space.
|
||||
.It Bq Er EINVAL
|
||||
The
|
||||
.Va tv_usec
|
||||
component of at least one of the values specified by the
|
||||
.Fa times
|
||||
argument has a value less than 0 or greater than 999999.
|
||||
.It Bq Er EIO
|
||||
An I/O error occurred while reading or writing the affected inode.
|
||||
.It Bq Er EPERM
|
||||
The
|
||||
.Fa times
|
||||
argument is not
|
||||
.Dv NULL
|
||||
nor are both
|
||||
.Va tv_nsec
|
||||
values
|
||||
.Dv UTIME_NOW ,
|
||||
nor are both
|
||||
.Va tv_nsec
|
||||
values
|
||||
.Dv UTIME_OMIT
|
||||
and the calling process's effective user ID
|
||||
does not match the owner of the file and is not the super-user.
|
||||
.It Bq Er EPERM
|
||||
The named file has its immutable or append-only flag set, see the
|
||||
.Xr chflags 2
|
||||
manual page for more information.
|
||||
.It Bq Er EROFS
|
||||
The file system containing the file is mounted read-only.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn futimens
|
||||
system call
|
||||
will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EBADF
|
||||
The
|
||||
.Fa fd
|
||||
argument
|
||||
does not refer to a valid descriptor.
|
||||
.El
|
||||
.Pp
|
||||
The
|
||||
.Fn utimensat
|
||||
system call
|
||||
will fail if:
|
||||
.Bl -tag -width Er
|
||||
.It Bq Er EACCES
|
||||
Search permission is denied for a component of the path prefix.
|
||||
.It Bq Er EBADF
|
||||
The
|
||||
.Fa path
|
||||
argument does not specify an absolute path and the
|
||||
.Fa fd
|
||||
argument is neither
|
||||
.Dv AT_FDCWD
|
||||
nor a valid file descriptor.
|
||||
.It Bq Er EFAULT
|
||||
The
|
||||
.Fa path
|
||||
argument
|
||||
points outside the process's allocated address space.
|
||||
.It Bq Er ELOOP
|
||||
Too many symbolic links were encountered in translating the pathname.
|
||||
.It Bq Er ENAMETOOLONG
|
||||
A component of a pathname exceeded
|
||||
.Dv NAME_MAX
|
||||
characters, or an entire path name exceeded
|
||||
.Dv PATH_MAX
|
||||
characters.
|
||||
.It Bq Er ENOENT
|
||||
The named file does not exist.
|
||||
.It Bq Er ENOTDIR
|
||||
A component of the path prefix is not a directory.
|
||||
.It Bq Er ENOTDIR
|
||||
The
|
||||
.Fa path
|
||||
argument is not an absolute path and
|
||||
.Fa fd
|
||||
is neither
|
||||
.Dv AT_FDCWD
|
||||
nor a file descriptor associated with a directory.
|
||||
.It Bq Er ENOTSUP
|
||||
The running kernel does not support this system call and
|
||||
.Dv AT_SYMLINK_NOFOLLOW
|
||||
is used with a path relative to a file descriptor.
|
||||
.El
|
||||
.Sh SEE ALSO
|
||||
.Xr chflags 2 ,
|
||||
.Xr stat 2 ,
|
||||
.Xr symlink 2 ,
|
||||
.Xr utimes 2 ,
|
||||
.Xr utime 3 ,
|
||||
.Xr symlink 7
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Fn futimens
|
||||
and
|
||||
.Fn utimensat
|
||||
system calls are expected to conform to
|
||||
.St -p1003.1-2008 .
|
||||
.Sh HISTORY
|
||||
The
|
||||
.Fn futimens
|
||||
and
|
||||
.Fn utimensat
|
||||
system calls appeared in
|
||||
.Fx 11.0 .
|
109
lib/libc/sys/utimensat.c
Normal file
109
lib/libc/sys/utimensat.c
Normal file
@ -0,0 +1,109 @@
|
||||
/*-
|
||||
* Copyright (c) 2015 Jilles Tjoelker
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "namespace.h"
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <time.h>
|
||||
#include "un-namespace.h"
|
||||
|
||||
#include "libc_private.h"
|
||||
|
||||
int
|
||||
utimensat(int fd, const char *path, const struct timespec times[2], int flag)
|
||||
{
|
||||
struct timeval now, tv[2], *tvp;
|
||||
struct stat sb;
|
||||
|
||||
if (__getosreldate() >= 1100056)
|
||||
return (__sys_utimensat(fd, path, times, flag));
|
||||
|
||||
if ((flag & ~AT_SYMLINK_NOFOLLOW) != 0) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if (times == NULL || (times[0].tv_nsec == UTIME_NOW &&
|
||||
times[1].tv_nsec == UTIME_NOW))
|
||||
tvp = NULL;
|
||||
else if (times[0].tv_nsec == UTIME_OMIT &&
|
||||
times[1].tv_nsec == UTIME_OMIT)
|
||||
return (0);
|
||||
else {
|
||||
if ((times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999) &&
|
||||
times[0].tv_nsec != UTIME_NOW &&
|
||||
times[0].tv_nsec != UTIME_OMIT) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
if ((times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999) &&
|
||||
times[1].tv_nsec != UTIME_NOW &&
|
||||
times[1].tv_nsec != UTIME_OMIT) {
|
||||
errno = EINVAL;
|
||||
return (-1);
|
||||
}
|
||||
tv[0].tv_sec = times[0].tv_sec;
|
||||
tv[0].tv_usec = times[0].tv_nsec / 1000;
|
||||
tv[1].tv_sec = times[1].tv_sec;
|
||||
tv[1].tv_usec = times[1].tv_nsec / 1000;
|
||||
tvp = tv;
|
||||
if (times[0].tv_nsec == UTIME_OMIT ||
|
||||
times[1].tv_nsec == UTIME_OMIT) {
|
||||
if (fstatat(fd, path, &sb, flag) == -1)
|
||||
return (-1);
|
||||
if (times[0].tv_nsec == UTIME_OMIT) {
|
||||
tv[0].tv_sec = sb.st_atim.tv_sec;
|
||||
tv[0].tv_usec = sb.st_atim.tv_nsec / 1000;
|
||||
}
|
||||
if (times[1].tv_nsec == UTIME_OMIT) {
|
||||
tv[1].tv_sec = sb.st_mtim.tv_sec;
|
||||
tv[1].tv_usec = sb.st_mtim.tv_nsec / 1000;
|
||||
}
|
||||
}
|
||||
if (times[0].tv_nsec == UTIME_NOW ||
|
||||
times[1].tv_nsec == UTIME_NOW) {
|
||||
if (gettimeofday(&now, NULL) == -1)
|
||||
return (-1);
|
||||
if (times[0].tv_nsec == UTIME_NOW)
|
||||
tv[0] = now;
|
||||
if (times[1].tv_nsec == UTIME_NOW)
|
||||
tv[1] = now;
|
||||
}
|
||||
}
|
||||
if ((flag & AT_SYMLINK_NOFOLLOW) == 0)
|
||||
return (futimesat(fd, path, tvp));
|
||||
else if ((flag & AT_SYMLINK_NOFOLLOW) != 0 &&
|
||||
(fd == AT_FDCWD || path[0] == '/'))
|
||||
return (lutimes(path, tvp));
|
||||
else {
|
||||
errno = ENOTSUP;
|
||||
return (-1);
|
||||
}
|
||||
}
|
@ -32,7 +32,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd September 23, 2013
|
||||
.Dd January 23, 2015
|
||||
.Dt RIGHTS 4
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -272,9 +272,13 @@ with the
|
||||
flag.
|
||||
.It Dv CAP_FUTIMES
|
||||
Permit
|
||||
.Xr futimes 2
|
||||
.Xr futimens 2
|
||||
and
|
||||
.Xr futimes 2 ,
|
||||
and permit
|
||||
.Xr futimesat 2
|
||||
and
|
||||
.Xr utimensat 2
|
||||
if the
|
||||
.Dv CAP_LOOKUP
|
||||
right is also present.
|
||||
|
@ -1299,6 +1299,49 @@ freebsd32_futimesat(struct thread *td, struct freebsd32_futimesat_args *uap)
|
||||
sp, UIO_SYSSPACE));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_futimens(struct thread *td, struct freebsd32_futimens_args *uap)
|
||||
{
|
||||
struct timespec32 ts32[2];
|
||||
struct timespec ts[2], *tsp;
|
||||
int error;
|
||||
|
||||
if (uap->times != NULL) {
|
||||
error = copyin(uap->times, ts32, sizeof(ts32));
|
||||
if (error)
|
||||
return (error);
|
||||
CP(ts32[0], ts[0], tv_sec);
|
||||
CP(ts32[0], ts[0], tv_nsec);
|
||||
CP(ts32[1], ts[1], tv_sec);
|
||||
CP(ts32[1], ts[1], tv_nsec);
|
||||
tsp = ts;
|
||||
} else
|
||||
tsp = NULL;
|
||||
return (kern_futimens(td, uap->fd, tsp, UIO_SYSSPACE));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_utimensat(struct thread *td, struct freebsd32_utimensat_args *uap)
|
||||
{
|
||||
struct timespec32 ts32[2];
|
||||
struct timespec ts[2], *tsp;
|
||||
int error;
|
||||
|
||||
if (uap->times != NULL) {
|
||||
error = copyin(uap->times, ts32, sizeof(ts32));
|
||||
if (error)
|
||||
return (error);
|
||||
CP(ts32[0], ts[0], tv_sec);
|
||||
CP(ts32[0], ts[0], tv_nsec);
|
||||
CP(ts32[1], ts[1], tv_sec);
|
||||
CP(ts32[1], ts[1], tv_nsec);
|
||||
tsp = ts;
|
||||
} else
|
||||
tsp = NULL;
|
||||
return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE,
|
||||
tsp, UIO_SYSSPACE, uap->flag));
|
||||
}
|
||||
|
||||
int
|
||||
freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap)
|
||||
{
|
||||
|
@ -1069,3 +1069,8 @@
|
||||
545 AUE_POLL STD { int freebsd32_ppoll(struct pollfd *fds, \
|
||||
u_int nfds, const struct timespec32 *ts, \
|
||||
const sigset_t *set); }
|
||||
546 AUE_FUTIMES STD { int freebsd32_futimens(int fd, \
|
||||
struct timespec *times); }
|
||||
547 AUE_FUTIMESAT STD { int freebsd32_utimensat(int fd, \
|
||||
char *path, \
|
||||
struct timespec *times, int flag); }
|
||||
|
@ -220,8 +220,9 @@ fsync
|
||||
ftruncate
|
||||
|
||||
##
|
||||
## Allow futimes(2), subject to capability rights.
|
||||
## Allow futimens(2) and futimes(2), subject to capability rights.
|
||||
##
|
||||
futimens
|
||||
futimes
|
||||
|
||||
##
|
||||
@ -453,6 +454,7 @@ readlinkat
|
||||
renameat
|
||||
symlinkat
|
||||
unlinkat
|
||||
utimensat
|
||||
|
||||
##
|
||||
## Allow entry into open(2). This system call will fail, since access to the
|
||||
|
@ -983,5 +983,10 @@
|
||||
545 AUE_POLL STD { int ppoll(struct pollfd *fds, u_int nfds, \
|
||||
const struct timespec *ts, \
|
||||
const sigset_t *set); }
|
||||
546 AUE_FUTIMES STD { int futimens(int fd, \
|
||||
struct timespec *times); }
|
||||
547 AUE_FUTIMESAT STD { int utimensat(int fd, \
|
||||
char *path, \
|
||||
struct timespec *times, int flag); }
|
||||
; Please copy any additions and changes to the following compatability tables:
|
||||
; sys/compat/freebsd32/syscalls.master
|
||||
|
@ -95,10 +95,12 @@ SDT_PROBE_DEFINE2(vfs, , stat, mode, "char *", "int");
|
||||
SDT_PROBE_DEFINE2(vfs, , stat, reg, "char *", "int");
|
||||
|
||||
static int chroot_refuse_vdir_fds(struct filedesc *fdp);
|
||||
static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
|
||||
static int kern_chflagsat(struct thread *td, int fd, const char *path,
|
||||
enum uio_seg pathseg, u_long flags, int atflag);
|
||||
static int setfflags(struct thread *td, struct vnode *, u_long);
|
||||
static int getutimes(const struct timeval *, enum uio_seg, struct timespec *);
|
||||
static int getutimens(const struct timespec *, enum uio_seg,
|
||||
struct timespec *, int *);
|
||||
static int setutimes(struct thread *td, struct vnode *,
|
||||
const struct timespec *, int, int);
|
||||
static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
|
||||
@ -3007,7 +3009,53 @@ getutimes(usrtvp, tvpseg, tsp)
|
||||
}
|
||||
|
||||
/*
|
||||
* Common implementation code for utimes(), lutimes(), and futimes().
|
||||
* Common implementation code for futimens(), utimensat().
|
||||
*/
|
||||
#define UTIMENS_NULL 0x1
|
||||
#define UTIMENS_EXIT 0x2
|
||||
static int
|
||||
getutimens(const struct timespec *usrtsp, enum uio_seg tspseg,
|
||||
struct timespec *tsp, int *retflags)
|
||||
{
|
||||
struct timespec tsnow;
|
||||
int error;
|
||||
|
||||
vfs_timestamp(&tsnow);
|
||||
*retflags = 0;
|
||||
if (usrtsp == NULL) {
|
||||
tsp[0] = tsnow;
|
||||
tsp[1] = tsnow;
|
||||
*retflags |= UTIMENS_NULL;
|
||||
return (0);
|
||||
}
|
||||
if (tspseg == UIO_SYSSPACE) {
|
||||
tsp[0] = usrtsp[0];
|
||||
tsp[1] = usrtsp[1];
|
||||
} else if ((error = copyin(usrtsp, tsp, sizeof(*tsp) * 2)) != 0)
|
||||
return (error);
|
||||
if (tsp[0].tv_nsec == UTIME_OMIT && tsp[1].tv_nsec == UTIME_OMIT)
|
||||
*retflags |= UTIMENS_EXIT;
|
||||
if (tsp[0].tv_nsec == UTIME_NOW && tsp[1].tv_nsec == UTIME_NOW)
|
||||
*retflags |= UTIMENS_NULL;
|
||||
if (tsp[0].tv_nsec == UTIME_OMIT)
|
||||
tsp[0].tv_sec = VNOVAL;
|
||||
else if (tsp[0].tv_nsec == UTIME_NOW)
|
||||
tsp[0] = tsnow;
|
||||
else if (tsp[0].tv_nsec < 0 || tsp[0].tv_nsec >= 1000000000L)
|
||||
return (EINVAL);
|
||||
if (tsp[1].tv_nsec == UTIME_OMIT)
|
||||
tsp[1].tv_sec = VNOVAL;
|
||||
else if (tsp[1].tv_nsec == UTIME_NOW)
|
||||
tsp[1] = tsnow;
|
||||
else if (tsp[1].tv_nsec < 0 || tsp[1].tv_nsec >= 1000000000L)
|
||||
return (EINVAL);
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Common implementation code for utimes(), lutimes(), futimes(), futimens(),
|
||||
* and utimensat().
|
||||
*/
|
||||
static int
|
||||
setutimes(td, vp, ts, numtimes, nullflag)
|
||||
@ -3196,6 +3244,80 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr,
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
sys_futimens(struct thread *td, struct futimens_args *uap)
|
||||
{
|
||||
|
||||
return (kern_futimens(td, uap->fd, uap->times, UIO_USERSPACE));
|
||||
}
|
||||
|
||||
int
|
||||
kern_futimens(struct thread *td, int fd, struct timespec *tptr,
|
||||
enum uio_seg tptrseg)
|
||||
{
|
||||
struct timespec ts[2];
|
||||
struct file *fp;
|
||||
cap_rights_t rights;
|
||||
int error, flags;
|
||||
|
||||
AUDIT_ARG_FD(fd);
|
||||
error = getutimens(tptr, tptrseg, ts, &flags);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
if (flags & UTIMENS_EXIT)
|
||||
return (0);
|
||||
error = getvnode(td->td_proc->p_fd, fd,
|
||||
cap_rights_init(&rights, CAP_FUTIMES), &fp);
|
||||
if (error != 0)
|
||||
return (error);
|
||||
#ifdef AUDIT
|
||||
vn_lock(fp->f_vnode, LK_SHARED | LK_RETRY);
|
||||
AUDIT_ARG_VNODE1(fp->f_vnode);
|
||||
VOP_UNLOCK(fp->f_vnode, 0);
|
||||
#endif
|
||||
error = setutimes(td, fp->f_vnode, ts, 2, flags & UTIMENS_NULL);
|
||||
fdrop(fp, td);
|
||||
return (error);
|
||||
}
|
||||
|
||||
int
|
||||
sys_utimensat(struct thread *td, struct utimensat_args *uap)
|
||||
{
|
||||
|
||||
return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE,
|
||||
uap->times, UIO_USERSPACE, uap->flag));
|
||||
}
|
||||
|
||||
int
|
||||
kern_utimensat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
|
||||
struct timespec *tptr, enum uio_seg tptrseg, int flag)
|
||||
{
|
||||
struct nameidata nd;
|
||||
struct timespec ts[2];
|
||||
int error, flags;
|
||||
|
||||
if (flag & ~AT_SYMLINK_NOFOLLOW)
|
||||
return (EINVAL);
|
||||
|
||||
if ((error = getutimens(tptr, tptrseg, ts, &flags)) != 0)
|
||||
return (error);
|
||||
NDINIT_AT(&nd, LOOKUP, ((flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW :
|
||||
FOLLOW) | AUDITVNODE1, pathseg, path, fd, td);
|
||||
if ((error = namei(&nd)) != 0)
|
||||
return (error);
|
||||
/*
|
||||
* We are allowed to call namei() regardless of 2xUTIME_OMIT.
|
||||
* POSIX states:
|
||||
* "If both tv_nsec fields are UTIME_OMIT... EACCESS may be detected."
|
||||
* "Search permission is denied by a component of the path prefix."
|
||||
*/
|
||||
NDFREE(&nd, NDF_ONLY_PNBUF);
|
||||
if ((flags & UTIMENS_EXIT) == 0)
|
||||
error = setutimes(td, nd.ni_vp, ts, 2, flags & UTIMENS_NULL);
|
||||
vrele(nd.ni_vp);
|
||||
return (error);
|
||||
}
|
||||
|
||||
/*
|
||||
* Truncate a file given its path name.
|
||||
*/
|
||||
|
@ -146,9 +146,9 @@
|
||||
#define CAP_FSTATAT (CAP_FSTAT | CAP_LOOKUP)
|
||||
/* Allows for fstatfs(2). */
|
||||
#define CAP_FSTATFS CAPRIGHT(0, 0x0000000000100000ULL)
|
||||
/* Allows for futimes(2). */
|
||||
/* Allows for futimens(2) and futimes(2). */
|
||||
#define CAP_FUTIMES CAPRIGHT(0, 0x0000000000200000ULL)
|
||||
/* Allows for futimes(2) and futimesat(2). */
|
||||
/* Allows for futimens(2), futimes(2), futimesat(2) and utimensat(2). */
|
||||
#define CAP_FUTIMESAT (CAP_FUTIMES | CAP_LOOKUP)
|
||||
/* Allows for linkat(2) and renameat(2) (destination directory descriptor). */
|
||||
#define CAP_LINKAT (CAP_LOOKUP | 0x0000000000400000ULL)
|
||||
|
@ -58,7 +58,7 @@
|
||||
* in the range 5 to 9.
|
||||
*/
|
||||
#undef __FreeBSD_version
|
||||
#define __FreeBSD_version 1100055 /* Master, propagated to newvers */
|
||||
#define __FreeBSD_version 1100056 /* Master, propagated to newvers */
|
||||
|
||||
/*
|
||||
* __FreeBSD_kernel__ indicates that this system uses the kernel of FreeBSD,
|
||||
|
@ -307,6 +307,11 @@ struct nstat {
|
||||
|
||||
#endif /* __BSD_VISIBLE */
|
||||
|
||||
#if __POSIX_VISIBLE >= 200809
|
||||
#define UTIME_NOW -1
|
||||
#define UTIME_OMIT -2
|
||||
#endif
|
||||
|
||||
#ifndef _KERNEL
|
||||
__BEGIN_DECLS
|
||||
#if __BSD_VISIBLE
|
||||
@ -322,6 +327,9 @@ int fchmod(int, mode_t);
|
||||
#endif
|
||||
#if __POSIX_VISIBLE >= 200809
|
||||
int fchmodat(int, const char *, mode_t, int);
|
||||
int futimens(int fd, const struct timespec times[2]);
|
||||
int utimensat(int fd, const char *path, const struct timespec times[2],
|
||||
int flag);
|
||||
#endif
|
||||
int fstat(int, struct stat *);
|
||||
#if __BSD_VISIBLE
|
||||
|
@ -99,6 +99,8 @@ int kern_fstatfs(struct thread *td, int fd, struct statfs *buf);
|
||||
int kern_ftruncate(struct thread *td, int fd, off_t length);
|
||||
int kern_futimes(struct thread *td, int fd, struct timeval *tptr,
|
||||
enum uio_seg tptrseg);
|
||||
int kern_futimens(struct thread *td, int fd, struct timespec *tptr,
|
||||
enum uio_seg tptrseg);
|
||||
int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count,
|
||||
long *basep, ssize_t *residp, enum uio_seg bufseg);
|
||||
int kern_getfsstat(struct thread *td, struct statfs **buf, size_t bufsize,
|
||||
@ -220,6 +222,9 @@ int kern_unlinkat(struct thread *td, int fd, char *path,
|
||||
enum uio_seg pathseg, ino_t oldinum);
|
||||
int kern_utimesat(struct thread *td, int fd, char *path,
|
||||
enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg);
|
||||
int kern_utimensat(struct thread *td, int fd, char *path,
|
||||
enum uio_seg pathseg, struct timespec *tptr, enum uio_seg tptrseg,
|
||||
int follow);
|
||||
int kern_wait(struct thread *td, pid_t pid, int *status, int options,
|
||||
struct rusage *rup);
|
||||
int kern_wait6(struct thread *td, enum idtype idtype, id_t id, int *status,
|
||||
|
@ -714,6 +714,7 @@ ktrsyscall(struct ktr_syscall *ktr, u_int flags)
|
||||
case SYS_readlinkat:
|
||||
case SYS_renameat:
|
||||
case SYS_unlinkat:
|
||||
case SYS_utimensat:
|
||||
putchar('(');
|
||||
atfdname(*ip, decimal);
|
||||
c = ',';
|
||||
|
Loading…
Reference in New Issue
Block a user