kern/181459: [patch] Addition of 'futimensat' call allowing to set file time with nanosecond precision

Yuri yuri at tsoft.com
Wed Aug 21 22:40:01 UTC 2013


>Number:         181459
>Category:       kern
>Synopsis:       [patch] Addition of 'futimensat' call allowing to set file time with nanosecond precision
>Confidential:   no
>Severity:       non-critical
>Priority:       low
>Responsible:    freebsd-bugs
>State:          open
>Quarter:        
>Keywords:       
>Date-Required:
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Wed Aug 21 22:40:00 UTC 2013
>Closed-Date:
>Last-Modified:
>Originator:     Yuri
>Release:        10
>Organization:
n/a
>Environment:
>Description:
This patch adds POSIX futimensat function, which is able to set the time of the file with nanosecond precision. Both by name and by file descriptor.

Times are handled internally in struct timespec, but the function allowing to set it was missing.
>How-To-Repeat:

>Fix:


Patch attached with submission follows:

Index: contrib/openbsm/etc/audit_event
===================================================================
--- contrib/openbsm/etc/audit_event	(revision 254587)
+++ contrib/openbsm/etc/audit_event	(working copy)
@@ -294,6 +294,7 @@
 299:AUE_PF_POLICY_FLUSH:Flush IPsec policy rules:ad
 300:AUE_PF_POLICY_ALGS:Update IPsec algorithms:ad
 301:AUE_PORTFS:portfs:fa
+302:AUE_FUTIMENSAT:futimensat(2):fm
 #
 # What follows are deprecated Darwin event numbers that may soon^H^H^H^Hnow
 # conflict with Solaris events.
Index: lib/libarchive/config_freebsd.h
===================================================================
--- lib/libarchive/config_freebsd.h	(revision 254587)
+++ lib/libarchive/config_freebsd.h	(working copy)
@@ -111,6 +111,7 @@
 #define HAVE_FTRUNCATE 1
 #define HAVE_FUTIMES 1
 #define HAVE_FUTIMESAT 1
+#define HAVE_FUTIMENSAT 1
 #define HAVE_GETEUID 1
 #define HAVE_GETGRGID_R 1
 #define HAVE_GETGRNAM_R 1
Index: lib/libc/sys/Makefile.inc
===================================================================
--- lib/libc/sys/Makefile.inc	(revision 254587)
+++ lib/libc/sys/Makefile.inc	(working copy)
@@ -397,6 +397,7 @@
 MLINKS+=unlink.2 unlinkat.2
 MLINKS+=utimes.2 futimes.2 \
 	utimes.2 futimesat.2 \
+	utimes.2 futimensat.2 \
 	utimes.2 lutimes.2
 MLINKS+=wait.2 wait3.2 \
 	wait.2 wait4.2 \
Index: lib/libc/sys/Symbol.map
===================================================================
--- lib/libc/sys/Symbol.map	(revision 254587)
+++ lib/libc/sys/Symbol.map	(working copy)
@@ -342,6 +342,7 @@
 	fexecve;
 	fstatat;
 	futimesat;
+	futimensat;
 	jail_get;
 	jail_set;
 	jail_remove;
Index: lib/libc/sys/cap_rights_limit.2
===================================================================
--- lib/libc/sys/cap_rights_limit.2	(revision 254587)
+++ lib/libc/sys/cap_rights_limit.2	(working copy)
@@ -250,8 +250,10 @@
 .It Dv CAP_FUTIMES
 Permit
 .Xr futimes 2
+,
+.Xr futimesat 2
 and
-.Xr futimesat 2 .
+.Xr futimensat 2 .
 .It Dv CAP_FUTIMESAT
 An alias to
 .Dv CAP_FUTIMES .
Index: lib/libc/sys/sigaction.2
===================================================================
--- lib/libc/sys/sigaction.2	(revision 254587)
+++ lib/libc/sys/sigaction.2	(working copy)
@@ -568,6 +568,7 @@
 .Fn flsl ,
 .Fn flsll ,
 .Fn futimesat ,
+.Fn futimensat ,
 .Fn pipe2 ,
 .Fn strlcat .
 .Fn strlcpy ,
Index: lib/libc/sys/utimes.2
===================================================================
--- lib/libc/sys/utimes.2	(revision 254587)
+++ lib/libc/sys/utimes.2	(working copy)
@@ -37,7 +37,8 @@
 .Nm utimes ,
 .Nm lutimes ,
 .Nm futimes ,
-.Nm futimesat
+.Nm futimesat ,
+.Nm futimensat
 .Nd set file access and modification times
 .Sh LIBRARY
 .Lb libc
@@ -51,6 +52,8 @@
 .Fn futimes "int fd" "const struct timeval *times"
 .Ft int
 .Fn futimesat "int fd" "const char *path" "const struct timeval times[2]"
+.Ft int
+.Fn futimensat "int fd" "const char *path" "const struct timespec times[2]"
 .Sh DESCRIPTION
 The access and modification times of the file named by
 .Fa path
@@ -122,6 +125,15 @@
 parameter, the current working directory is used and the behavior is identical to
 a call to
 .Fn utimes .
+.Pp
+The
+.Fn futimensat
+system call sets the file access and modification times with nanosecond precision. Also when
+.Fa path
+argument is
+.Dv NULL ,
+it changes times of the file referenced by
+.Fa fd .
 .Sh RETURN VALUES
 .Rv -std
 .Sh ERRORS
Index: sys/bsm/audit_kevents.h
===================================================================
--- sys/bsm/audit_kevents.h	(revision 254587)
+++ sys/bsm/audit_kevents.h	(working copy)
@@ -314,6 +314,7 @@
 #define	AUE_PF_POLICY_FLUSH	299	/* Solaris-specific. */
 #define	AUE_PF_POLICY_ALGS	300	/* Solaris-specific. */
 #define	AUE_PORTFS		301	/* Solaris-specific. */
+#define	AUE_FUTIMENSAT		302
 
 /*
  * Events added for Apple Darwin that potentially collide with future Solaris
Index: sys/kern/capabilities.conf
===================================================================
--- sys/kern/capabilities.conf	(revision 254587)
+++ sys/kern/capabilities.conf	(working copy)
@@ -452,6 +452,7 @@
 fchownat
 fstatat
 futimesat
+futimensat
 linkat
 mkdirat
 mkfifoat
Index: sys/kern/init_sysent.c
===================================================================
--- sys/kern/init_sysent.c	(revision 254587)
+++ sys/kern/init_sysent.c	(working copy)
@@ -578,4 +578,5 @@
 	{ AS(accept4_args), (sy_call_t *)sys_accept4, AUE_ACCEPT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 541 = accept4 */
 	{ AS(pipe2_args), (sy_call_t *)sys_pipe2, AUE_PIPE, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 542 = pipe2 */
 	{ AS(aio_mlock_args), (sy_call_t *)lkmressys, AUE_NULL, NULL, 0, 0, 0, SY_THR_ABSENT },	/* 543 = aio_mlock */
+	{ AS(futimensat_args), (sy_call_t *)sys_futimensat, AUE_FUTIMENSAT, NULL, 0, 0, SYF_CAPENABLED, SY_THR_STATIC },	/* 544 = futimensat */
 };
Index: sys/kern/syscalls.c
===================================================================
--- sys/kern/syscalls.c	(revision 254587)
+++ sys/kern/syscalls.c	(working copy)
@@ -551,4 +551,5 @@
 	"accept4",			/* 541 = accept4 */
 	"pipe2",			/* 542 = pipe2 */
 	"aio_mlock",			/* 543 = aio_mlock */
+	"futimensat",			/* 544 = futimensat */
 };
Index: sys/kern/syscalls.master
===================================================================
--- sys/kern/syscalls.master	(revision 254587)
+++ sys/kern/syscalls.master	(working copy)
@@ -978,5 +978,7 @@
 				    int flags); }
 542	AUE_PIPE	STD	{ int pipe2(int *fildes, int flags); }
 543	AUE_NULL	NOSTD	{ int aio_mlock(struct aiocb *aiocbp); }
+544	AUE_NULL	NOSTD	{ int futimensat(int fd, char *path, \
+				    struct timespec *times); }
 ; Please copy any additions and changes to the following compatability tables:
 ; sys/compat/freebsd32/syscalls.master
Index: sys/kern/vfs_syscalls.c
===================================================================
--- sys/kern/vfs_syscalls.c	(revision 254587)
+++ sys/kern/vfs_syscalls.c	(working copy)
@@ -106,6 +106,8 @@
     const struct timespec *, int, int);
 static int vn_access(struct vnode *vp, int user_flags, struct ucred *cred,
     struct thread *td);
+static int timesat_common(struct thread *td, int fd,
+    char *path, enum uio_seg pathseg, struct timespec *ts, int nullflag);
 
 /*
  * The module initialization routine for POSIX asynchronous I/O will
@@ -3194,6 +3196,11 @@
 	const char * path;
 	const struct timeval * times;
 };
+struct futimensat_args {
+	int fd;
+	const char * path;
+	const struct timespec * times;
+};
 #endif
 int
 sys_futimesat(struct thread *td, struct futimesat_args *uap)
@@ -3204,6 +3211,35 @@
 }
 
 int
+sys_futimensat(struct thread *td, struct futimensat_args *uap)
+{
+
+	struct timespec ts[2];
+	int error;
+
+	if (uap->times == NULL) {
+		vfs_timestamp(&ts[0]);
+		ts[1] = ts[0];
+	} else {
+		if ((error = copyin(uap->times, ts, sizeof(ts))) != 0)
+			return (error);
+
+		if (ts[0].tv_nsec < 0 || ts[0].tv_nsec >= 1000000000 ||
+		    ts[1].tv_nsec < 0 || ts[1].tv_nsec >= 1000000000)
+			return (EINVAL);
+	}
+
+	if (uap->path != NULL) {
+		/* if path is set, file is specified by name */
+		return (timesat_common(td, uap->fd, uap->path, UIO_USERSPACE,
+				       ts, uap->times == NULL));
+	} else {
+		/* if path is NULL, file is specified by fd */
+		return (kern_futimens(td, uap->fd, ts));
+	}
+}
+
+int
 kern_utimes(struct thread *td, char *path, enum uio_seg pathseg,
     struct timeval *tptr, enum uio_seg tptrseg)
 {
@@ -3215,12 +3251,22 @@
 kern_utimesat(struct thread *td, int fd, char *path, enum uio_seg pathseg,
     struct timeval *tptr, enum uio_seg tptrseg)
 {
-	struct nameidata nd;
 	struct timespec ts[2];
 	int error;
 
 	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
 		return (error);
+
+	return (timesat_common(td, fd, path, pathseg, ts, tptr == NULL));
+}
+
+static int
+timesat_common(struct thread *td, int fd, char *path, enum uio_seg pathseg,
+    struct timespec *ts, int nullflag)
+{
+	struct nameidata nd;
+	int error;
+
 	NDINIT_ATRIGHTS(&nd, LOOKUP, FOLLOW | AUDITVNODE1, pathseg, path, fd,
 	    CAP_FUTIMES, td);
 
@@ -3227,7 +3273,7 @@
 	if ((error = namei(&nd)) != 0)
 		return (error);
 	NDFREE(&nd, NDF_ONLY_PNBUF);
-	error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL);
+	error = setutimes(td, nd.ni_vp, ts, 2, nullflag);
 	vrele(nd.ni_vp);
 	return (error);
 }
@@ -3299,12 +3345,21 @@
     enum uio_seg tptrseg)
 {
 	struct timespec ts[2];
+	int error;
+
+	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
+		return (error);
+
+	return (kern_futimens(td, fd, ts));
+}
+
+int
+kern_futimens(struct thread *td, int fd, struct timespec *ts)
+{
 	struct file *fp;
 	int error;
 
 	AUDIT_ARG_FD(fd);
-	if ((error = getutimes(tptr, tptrseg, ts)) != 0)
-		return (error);
 	if ((error = getvnode(td->td_proc->p_fd, fd, CAP_FUTIMES, &fp)) != 0)
 		return (error);
 #ifdef AUDIT
@@ -3312,7 +3367,7 @@
 	AUDIT_ARG_VNODE1(fp->f_vnode);
 	VOP_UNLOCK(fp->f_vnode, 0);
 #endif
-	error = setutimes(td, fp->f_vnode, ts, 2, tptr == NULL);
+	error = setutimes(td, fp->f_vnode, ts, 2, ts == NULL);
 	fdrop(fp, td);
 	return (error);
 }
Index: sys/sys/capability.h
===================================================================
--- sys/sys/capability.h	(revision 254587)
+++ sys/sys/capability.h	(working copy)
@@ -116,6 +116,7 @@
 #define	CAP_FSTATFS		0x0000000000020000ULL
 #define	CAP_FUTIMES		0x0000000000040000ULL
 #define	CAP_FUTIMESAT		CAP_FUTIMES
+#define	CAP_FUTIMENSAT		CAP_FUTIMES
 #define	CAP_LINKAT		0x0000000000400000ULL
 #define	CAP_MKDIRAT		0x0000000000200000ULL
 #define	CAP_MKFIFOAT		0x0000000000800000ULL
Index: sys/sys/syscall.h
===================================================================
--- sys/sys/syscall.h	(revision 254587)
+++ sys/sys/syscall.h	(working copy)
@@ -463,4 +463,5 @@
 #define	SYS_accept4	541
 #define	SYS_pipe2	542
 #define	SYS_aio_mlock	543
-#define	SYS_MAXSYSCALL	544
+#define	SYS_futimensat	544
+#define	SYS_MAXSYSCALL	545
Index: sys/sys/syscall.mk
===================================================================
--- sys/sys/syscall.mk	(revision 254587)
+++ sys/sys/syscall.mk	(working copy)
@@ -364,6 +364,7 @@
 	fexecve.o \
 	fstatat.o \
 	futimesat.o \
+	futimensat.o \
 	linkat.o \
 	mkdirat.o \
 	mkfifoat.o \
Index: sys/sys/syscallsubr.h
===================================================================
--- sys/sys/syscallsubr.h	(revision 254587)
+++ sys/sys/syscallsubr.h	(working copy)
@@ -104,6 +104,7 @@
 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 *ts);
 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,
Index: sys/sys/sysproto.h
===================================================================
--- sys/sys/sysproto.h	(revision 254587)
+++ sys/sys/sysproto.h	(working copy)
@@ -1579,6 +1579,11 @@
 	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
 	char times_l_[PADL_(struct timeval *)]; struct timeval * times; char times_r_[PADR_(struct timeval *)];
 };
+struct futimensat_args {
+	char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)];
+	char path_l_[PADL_(char *)]; char * path; char path_r_[PADR_(char *)];
+	char times_l_[PADL_(struct timespec *)]; struct timespec * times; char times_r_[PADR_(struct timespec *)];
+};
 struct linkat_args {
 	char fd1_l_[PADL_(int)]; int fd1; char fd1_r_[PADR_(int)];
 	char path1_l_[PADL_(char *)]; char * path1; char path1_r_[PADR_(char *)];
@@ -2160,6 +2165,7 @@
 int	sys_fexecve(struct thread *, struct fexecve_args *);
 int	sys_fstatat(struct thread *, struct fstatat_args *);
 int	sys_futimesat(struct thread *, struct futimesat_args *);
+int	sys_futimensat(struct thread *, struct futimensat_args *);
 int	sys_linkat(struct thread *, struct linkat_args *);
 int	sys_mkdirat(struct thread *, struct mkdirat_args *);
 int	sys_mkfifoat(struct thread *, struct mkfifoat_args *);
@@ -2867,6 +2873,7 @@
 #define	SYS_AUE_fexecve	AUE_FEXECVE
 #define	SYS_AUE_fstatat	AUE_FSTATAT
 #define	SYS_AUE_futimesat	AUE_FUTIMESAT
+#define	SYS_AUE_futimensat	AUE_FUTIMENSAT
 #define	SYS_AUE_linkat	AUE_LINKAT
 #define	SYS_AUE_mkdirat	AUE_MKDIRAT
 #define	SYS_AUE_mkfifoat	AUE_MKFIFOAT
Index: sys/sys/time.h
===================================================================
--- sys/sys/time.h	(revision 254587)
+++ sys/sys/time.h	(working copy)
@@ -480,6 +480,7 @@
 int	clock_getcpuclockid2(id_t, int, clockid_t *);
 int	futimes(int, const struct timeval *);
 int	futimesat(int, const char *, const struct timeval [2]);
+int	futimensat(int, const char *, const struct timespec [2]);
 int	lutimes(const char *, const struct timeval *);
 int	settimeofday(const struct timeval *, const struct timezone *);
 #endif


>Release-Note:
>Audit-Trail:
>Unformatted:


More information about the freebsd-bugs mailing list