>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:
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/freebsd-bugs
To unsubscribe, send any mail to "[email protected]"

Reply via email to