diff --git a/lib/libc/sys/Makefile.inc b/lib/libc/sys/Makefile.inc index 073220e..70456e5 100644 --- a/lib/libc/sys/Makefile.inc +++ b/lib/libc/sys/Makefile.inc @@ -213,5 +213,6 @@ MLINKS+=timer_settime.2 timer_getoverrun.2 timer_settime.2 timer_gettime.2 MLINKS+=truncate.2 ftruncate.2 MLINKS+=unlink.2 unlinkat.2 MLINKS+=utimes.2 futimes.2 utimes.2 futimesat.2 utimes.2 lutimes.2 +MLINKS+=utimes.2 futimens.2 utimes.2 utimensat.2 MLINKS+=wait.2 wait3.2 wait.2 wait4.2 wait.2 waitpid.2 MLINKS+=write.2 pwrite.2 write.2 pwritev.2 write.2 writev.2 diff --git a/lib/libc/sys/Symbol.map b/lib/libc/sys/Symbol.map index f1c1567..0bd46b9 100644 --- a/lib/libc/sys/Symbol.map +++ b/lib/libc/sys/Symbol.map @@ -383,6 +383,8 @@ FBSD_1.2 { FBSD_1.3 { posix_fadvise; + futimens; + utimensat; }; FBSDprivate_1.0 { diff --git a/lib/libc/sys/utimes.2 b/lib/libc/sys/utimes.2 index 74a7dd0..0bbcb2c 100644 --- a/lib/libc/sys/utimes.2 +++ b/lib/libc/sys/utimes.2 @@ -30,14 +30,16 @@ .\" @(#)utimes.2 8.1 (Berkeley) 6/4/93 .\" $FreeBSD$ .\" -.Dd April 10, 2008 +.Dd March 5, 2012 .Dt UTIMES 2 .Os .Sh NAME .Nm utimes , .Nm lutimes , .Nm futimes , -.Nm futimesat +.Nm futimesat , +.Nm utimensat , +.Nm futimens .Nd set file access and modification times .Sh LIBRARY .Lb libc @@ -51,6 +53,11 @@ .Fn futimes "int fd" "const struct timeval *times" .Ft int .Fn futimesat "int fd" "const char *path" "const struct timeval times[2]" +.In sys/stat.h +.Ft int +.Fn utimensat "int fd" "const char *file" "const struct timespec times[2]" "int flag" +.Ft int +.Fn futimens "int fd" "const struct timespec times[2]" .Sh DESCRIPTION The access and modification times of the file named by .Fa path @@ -115,6 +122,8 @@ descriptor instead of the current working directory. If .Fn futimesat +or +.Fn utimensat is passed the special value .Dv AT_FDCWD in the @@ -122,6 +131,58 @@ in the parameter, the current working directory is used and the behavior is identical to a call to .Fn utimes . +.Pp +The +.Fn utimensat +and +.Fn futimens +are equivalent to +.Fn utimes +and +.Fn futimes , +respectively, with the following differences. +.Pp +Both +.Fn utimensat +and +.Fn futimens +take two timespec values instead of two timeval values. +Further, either of the +.Fa tv_nsec +fields can be set to one of the following special values defined in +.In sys/stat.h : +.Pp +.Bl -tag -width UTIME_OMIT -offset indent -compact +.It Dv UTIME_NOW +Set the respective timestamp to the greatest value supported +that is not greater than the current time. +.It Dv UTIME_OMIT +Do not change the respective timestamp. +.El +.Pp +Additionally, if the +.Fa path +argument to +.Fn utimensat +specifies a relative path, +the file whose timestamps are changed is determined relative to +the directory associated with file descriptor +.Fa fd +instead of the current working directory. +.Pp +Values for +.Fa flag +are constructed by bitwise-inclusive +.Tn OR Ns ing +flags from the following list defined in +.In fcntl.h : +.Pp +.Bl -tag -width AT_SYMLINK_NOFOLLOW -offset indent -compact +.It Dv AT_SYMLINK_NOFOLLOW +If +.Fa path +names a symbolic link, then the timestamps of the symbolic link are changed. +.El .Sh RETURN VALUES .Rv -std .Sh ERRORS @@ -258,6 +319,12 @@ function is expected to conform to The .Fn futimesat system call follows The Open Group Extended API Set 2 specification. +The +.Fn futimens +and +.Fn utimensat +system calls is expected to conform to +.St -p1003.1-2008 . .Sh HISTORY The .Fn utimes @@ -273,3 +340,9 @@ The .Fn futimesat system call appeared in .Fx 8.0 . +The +.Fn futimens +and +.Fn utimensat +system calls appeared in +.Fx 10.0 . diff --git a/sys/bsm/audit_kevents.h b/sys/bsm/audit_kevents.h index f4f77a5..ed311cd 100644 --- a/sys/bsm/audit_kevents.h +++ b/sys/bsm/audit_kevents.h @@ -602,6 +602,8 @@ #define AUE_PDKILL 43198 /* FreeBSD. */ #define AUE_PDGETPID 43199 /* FreeBSD. */ #define AUE_PDWAIT 43200 /* FreeBSD. */ +#define AUE_FUTIMENS 43201 /* FreeBSD. */ +#define AUE_UTIMENSAT 43202 /* FreeBSD. */ /* * Darwin BSM uses a number of AUE_O_* definitions, which are aliased to the diff --git a/sys/compat/freebsd32/freebsd32_misc.c b/sys/compat/freebsd32/freebsd32_misc.c index aff280a..36abe3b 100644 --- a/sys/compat/freebsd32/freebsd32_misc.c +++ b/sys/compat/freebsd32/freebsd32_misc.c @@ -1337,6 +1337,49 @@ freebsd32_futimesat(struct thread *td, struct freebsd32_futimesat_args *uap) } int +freebsd32_futimens(struct thread *td, struct freebsd32_futimens_args *uap) +{ + struct timespec32 s32[2]; + struct timespec s[2], *sp; + int error; + + if (uap->times != NULL) { + error = copyin(uap->times, s32, sizeof(s32)); + if (error) + return (error); + CP(s32[0], s[0], tv_sec); + CP(s32[0], s[0], tv_nsec); + CP(s32[1], s[1], tv_sec); + CP(s32[1], s[1], tv_nsec); + sp = s; + } else + sp = NULL; + return (kern_futimens(td, uap->fd, sp, UIO_SYSSPACE)); +} + +int +freebsd32_utimensat(struct thread *td, struct freebsd32_utimensat_args *uap) +{ + struct timespec32 s32[2]; + struct timespec s[2], *sp; + int error; + + if (uap->times != NULL) { + error = copyin(uap->times, s32, sizeof(s32)); + if (error) + return (error); + CP(s32[0], s[0], tv_sec); + CP(s32[0], s[0], tv_nsec); + CP(s32[1], s[1], tv_sec); + CP(s32[1], s[1], tv_nsec); + sp = s; + } else + sp = NULL; + return (kern_utimensat(td, uap->fd, uap->path, UIO_USERSPACE, + sp, UIO_SYSSPACE, uap->flag)); +} + +int freebsd32_adjtime(struct thread *td, struct freebsd32_adjtime_args *uap) { struct timeval32 tv32; diff --git a/sys/compat/freebsd32/freebsd32_proto.h b/sys/compat/freebsd32/freebsd32_proto.h index 1d6310b..3b4c0e6 100644 --- a/sys/compat/freebsd32/freebsd32_proto.h +++ b/sys/compat/freebsd32/freebsd32_proto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ #ifndef _FREEBSD32_SYSPROTO_H_ @@ -589,6 +589,16 @@ struct freebsd32_posix_fadvise_args { char len2_l_[PADL_(uint32_t)]; uint32_t len2; char len2_r_[PADR_(uint32_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; +struct freebsd32_utimensat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char times_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * times; char times_r_[PADR_(const struct timespec32 *)]; + char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)]; +}; +struct freebsd32_futimens_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char times_l_[PADL_(const struct timespec32 *)]; const struct timespec32 * times; char times_r_[PADR_(const struct timespec32 *)]; +}; #if !defined(PAD64_REQUIRED) && defined(__powerpc__) #define PAD64_REQUIRED #endif @@ -700,6 +710,8 @@ int freebsd32_shmctl(struct thread *, struct freebsd32_shmctl_args *); int freebsd32_pselect(struct thread *, struct freebsd32_pselect_args *); int freebsd32_posix_fallocate(struct thread *, struct freebsd32_posix_fallocate_args *); int freebsd32_posix_fadvise(struct thread *, struct freebsd32_posix_fadvise_args *); +int freebsd32_utimensat(struct thread *, struct freebsd32_utimensat_args *); +int freebsd32_futimens(struct thread *, struct freebsd32_futimens_args *); #ifdef COMPAT_43 @@ -1076,6 +1088,8 @@ int freebsd7_freebsd32_shmctl(struct thread *, struct freebsd7_freebsd32_shmctl_ #define FREEBSD32_SYS_AUE_freebsd32_pselect AUE_SELECT #define FREEBSD32_SYS_AUE_freebsd32_posix_fallocate AUE_NULL #define FREEBSD32_SYS_AUE_freebsd32_posix_fadvise AUE_NULL +#define FREEBSD32_SYS_AUE_freebsd32_utimensat AUE_UTIMENSAT +#define FREEBSD32_SYS_AUE_freebsd32_futimens AUE_FUTIMENS #undef PAD_ #undef PADL_ diff --git a/sys/compat/freebsd32/freebsd32_syscall.h b/sys/compat/freebsd32/freebsd32_syscall.h index d21b583..228ab90 100644 --- a/sys/compat/freebsd32/freebsd32_syscall.h +++ b/sys/compat/freebsd32/freebsd32_syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ #define FREEBSD32_SYS_syscall 0 @@ -428,4 +428,6 @@ #define FREEBSD32_SYS_rctl_remove_rule 529 #define FREEBSD32_SYS_freebsd32_posix_fallocate 530 #define FREEBSD32_SYS_freebsd32_posix_fadvise 531 -#define FREEBSD32_SYS_MAXSYSCALL 532 +#define FREEBSD32_SYS_freebsd32_utimensat 532 +#define FREEBSD32_SYS_freebsd32_futimens 533 +#define FREEBSD32_SYS_MAXSYSCALL 534 diff --git a/sys/compat/freebsd32/freebsd32_syscalls.c b/sys/compat/freebsd32/freebsd32_syscalls.c index c58a414..2a7c327 100644 --- a/sys/compat/freebsd32/freebsd32_syscalls.c +++ b/sys/compat/freebsd32/freebsd32_syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ const char *freebsd32_syscallnames[] = { @@ -555,4 +555,6 @@ const char *freebsd32_syscallnames[] = { "rctl_remove_rule", /* 529 = rctl_remove_rule */ "freebsd32_posix_fallocate", /* 530 = freebsd32_posix_fallocate */ "freebsd32_posix_fadvise", /* 531 = freebsd32_posix_fadvise */ + "freebsd32_utimensat", /* 532 = freebsd32_utimensat */ + "freebsd32_futimens", /* 533 = freebsd32_futimens */ }; diff --git a/sys/compat/freebsd32/freebsd32_sysent.c b/sys/compat/freebsd32/freebsd32_sysent.c index 4371d16..bcaea28 100644 --- a/sys/compat/freebsd32/freebsd32_sysent.c +++ b/sys/compat/freebsd32/freebsd32_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/compat/freebsd32/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ #include "opt_compat.h" @@ -592,4 +592,6 @@ struct sysent freebsd32_sysent[] = { { AS(rctl_remove_rule_args), (sy_call_t *)sys_rctl_remove_rule, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 529 = rctl_remove_rule */ { AS(freebsd32_posix_fallocate_args), (sy_call_t *)freebsd32_posix_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 530 = freebsd32_posix_fallocate */ { AS(freebsd32_posix_fadvise_args), (sy_call_t *)freebsd32_posix_fadvise, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 531 = freebsd32_posix_fadvise */ + { AS(freebsd32_utimensat_args), (sy_call_t *)freebsd32_utimensat, AUE_UTIMENSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 532 = freebsd32_utimensat */ + { AS(freebsd32_futimens_args), (sy_call_t *)freebsd32_futimens, AUE_FUTIMENS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 533 = freebsd32_futimens */ }; diff --git a/sys/compat/freebsd32/freebsd32_systrace_args.c b/sys/compat/freebsd32/freebsd32_systrace_args.c index 7f6bf68..f3c0953 100644 --- a/sys/compat/freebsd32/freebsd32_systrace_args.c +++ b/sys/compat/freebsd32/freebsd32_systrace_args.c @@ -3067,6 +3067,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 6; break; } + /* freebsd32_utimensat */ + case 532: { + struct freebsd32_utimensat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* const char * */ + uarg[2] = (intptr_t) p->times; /* const struct timespec32 * */ + iarg[3] = p->flag; /* int */ + *n_args = 4; + break; + } + /* freebsd32_futimens */ + case 533: { + struct freebsd32_futimens_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->times; /* const struct timespec32 * */ + *n_args = 2; + break; + } default: *n_args = 0; break; @@ -8181,6 +8199,38 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* freebsd32_utimensat */ + case 532: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const char *"; + break; + case 2: + p = "const struct timespec32 *"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; + /* freebsd32_futimens */ + case 533: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const struct timespec32 *"; + break; + default: + break; + }; + break; default: break; }; @@ -9933,6 +9983,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* freebsd32_utimensat */ + case 532: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* freebsd32_futimens */ + case 533: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/compat/freebsd32/syscalls.master b/sys/compat/freebsd32/syscalls.master index b80fd9c..4c61f24 100644 --- a/sys/compat/freebsd32/syscalls.master +++ b/sys/compat/freebsd32/syscalls.master @@ -997,3 +997,8 @@ uint32_t offset1, uint32_t offset2,\ uint32_t len1, uint32_t len2, \ int advice); } +532 AUE_UTIMENSAT STD { int freebsd32_utimensat(int fd, const char *path, \ + const struct timespec32 *times, int flag); } +533 AUE_FUTIMENS STD { int freebsd32_futimens(int fd, \ + const struct timespec32 *times); } + diff --git a/sys/kern/init_sysent.c b/sys/kern/init_sysent.c index 7ace326..f301140 100644 --- a/sys/kern/init_sysent.c +++ b/sys/kern/init_sysent.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ #include "opt_compat.h" @@ -566,4 +566,6 @@ struct sysent sysent[] = { { AS(rctl_remove_rule_args), (sy_call_t *)sys_rctl_remove_rule, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 529 = rctl_remove_rule */ { AS(posix_fallocate_args), (sy_call_t *)sys_posix_fallocate, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 530 = posix_fallocate */ { AS(posix_fadvise_args), (sy_call_t *)sys_posix_fadvise, AUE_NULL, NULL, 0, 0, 0, SY_THR_STATIC }, /* 531 = posix_fadvise */ + { AS(utimensat_args), (sy_call_t *)sys_utimensat, AUE_UTIMENSAT, NULL, 0, 0, 0, SY_THR_STATIC }, /* 532 = utimensat */ + { AS(futimens_args), (sy_call_t *)sys_futimens, AUE_FUTIMENS, NULL, 0, 0, 0, SY_THR_STATIC }, /* 533 = futimens */ }; diff --git a/sys/kern/syscalls.c b/sys/kern/syscalls.c index dd82db7..ac7a470 100644 --- a/sys/kern/syscalls.c +++ b/sys/kern/syscalls.c @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ const char *syscallnames[] = { @@ -539,4 +539,6 @@ const char *syscallnames[] = { "rctl_remove_rule", /* 529 = rctl_remove_rule */ "posix_fallocate", /* 530 = posix_fallocate */ "posix_fadvise", /* 531 = posix_fadvise */ + "utimensat", /* 532 = utimensat */ + "futimens", /* 533 = futimens */ }; diff --git a/sys/kern/syscalls.master b/sys/kern/syscalls.master index e10af89..4ad4481 100644 --- a/sys/kern/syscalls.master +++ b/sys/kern/syscalls.master @@ -951,5 +951,9 @@ off_t offset, off_t len); } 531 AUE_NULL STD { int posix_fadvise(int fd, off_t offset, \ off_t len, int advice); } +532 AUE_UTIMENSAT STD { int utimensat(int fd, const char *path, \ + const struct timespec *times, int flag); } +533 AUE_FUTIMENS STD { int futimens(int fd, \ + const struct timespec *times); } ; Please copy any additions and changes to the following compatability tables: ; sys/compat/freebsd32/syscalls.master diff --git a/sys/kern/systrace_args.c b/sys/kern/systrace_args.c index 4a5d72a..1b7d2d7 100644 --- a/sys/kern/systrace_args.c +++ b/sys/kern/systrace_args.c @@ -3265,6 +3265,24 @@ systrace_args(int sysnum, void *params, uint64_t *uarg, int *n_args) *n_args = 4; break; } + /* utimensat */ + case 532: { + struct utimensat_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->path; /* const char * */ + uarg[2] = (intptr_t) p->times; /* const struct timespec * */ + iarg[3] = p->flag; /* int */ + *n_args = 4; + break; + } + /* futimens */ + case 533: { + struct futimens_args *p = params; + iarg[0] = p->fd; /* int */ + uarg[1] = (intptr_t) p->times; /* const struct timespec * */ + *n_args = 2; + break; + } default: *n_args = 0; break; @@ -8683,6 +8701,38 @@ systrace_entry_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) break; }; break; + /* utimensat */ + case 532: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const char *"; + break; + case 2: + p = "const struct timespec *"; + break; + case 3: + p = "int"; + break; + default: + break; + }; + break; + /* futimens */ + case 533: + switch(ndx) { + case 0: + p = "int"; + break; + case 1: + p = "const struct timespec *"; + break; + default: + break; + }; + break; default: break; }; @@ -10566,6 +10616,16 @@ systrace_return_setargdesc(int sysnum, int ndx, char *desc, size_t descsz) if (ndx == 0 || ndx == 1) p = "int"; break; + /* utimensat */ + case 532: + if (ndx == 0 || ndx == 1) + p = "int"; + break; + /* futimens */ + case 533: + if (ndx == 0 || ndx == 1) + p = "int"; + break; default: break; }; diff --git a/sys/kern/vfs_syscalls.c b/sys/kern/vfs_syscalls.c index 9b7cbe4..2eeac75 100644 --- a/sys/kern/vfs_syscalls.c +++ b/sys/kern/vfs_syscalls.c @@ -3430,6 +3430,138 @@ kern_futimes(struct thread *td, int fd, struct timeval *tptr, } /* + * Common implementation code for futimens() and utimensat(). + */ +static int +getutimens(const struct timespec *usrtsp, enum uio_seg tspseg, + struct timespec *tsp) +{ + int error; + struct timespec now; + + if (usrtsp == NULL) { + vfs_timestamp(&tsp[0]); + tsp[1] = tsp[0]; + } else { + if (tspseg == UIO_SYSSPACE) { + tsp[0] = usrtsp[0]; + tsp[1] = usrtsp[1]; + } else { + if ((error = copyin(usrtsp, tsp, 2 * sizeof(*tsp))) != 0) + return (error); + } + + if (tsp[0].tv_nsec == UTIME_NOW || tsp[1].tv_nsec == UTIME_NOW) { + vfs_timestamp(&now); + if (tsp[0].tv_nsec == UTIME_NOW) + tsp[0] = now; + if (tsp[1].tv_nsec == UTIME_NOW) + tsp[1] = now; + } + + if (tsp[0].tv_nsec == UTIME_OMIT) { + tsp[0].tv_sec = VNOVAL; + tsp[0].tv_nsec = 0; + } + if (tsp[1].tv_nsec == UTIME_OMIT) { + tsp[1].tv_sec = VNOVAL; + tsp[1].tv_nsec = 0; + } + + if (tsp[0].tv_nsec >= 1000000000 || tsp[0].tv_nsec < 0 || + tsp[1].tv_nsec >= 1000000000 || tsp[1].tv_nsec < 0) + return (EINVAL); + } + return (0); +} + +/* + * Set the access and modification times of a file. + */ +#ifndef _SYS_SYSPROTO_H_ +struct sys_futimens_args { + int fd; + const struct timespec * times; +}; +#endif +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, const struct timespec *tptr, + enum uio_seg tptrseg) +{ + struct timespec ts[2]; + struct file *fp; + int vfslocked; + int error; + + AUDIT_ARG_FD(fd); + if ((error = getutimens(tptr, tptrseg, ts)) != 0) + return (error); + if ((error = getvnode(td->td_proc->p_fd, fd, CAP_FUTIMES, &fp)) + != 0) + return (error); + vfslocked = VFS_LOCK_GIANT(fp->f_vnode->v_mount); +#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, tptr == NULL); + VFS_UNLOCK_GIANT(vfslocked); + fdrop(fp, td); + return (error); +} + +#ifndef _SYS_SYSPROTO_H_ +struct utimensat_args { + int fd; + const char *path; + const struct timespec * times; + int flag; +}; +#endif +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, const char *path, enum uio_seg pathseg, + const struct timespec *tptr, enum uio_seg tptrseg, int flag) +{ + struct nameidata nd; + struct timespec ts[2]; + int error, follow, vfslocked; + + if (flag & ~AT_SYMLINK_NOFOLLOW) + return (EINVAL); + follow = (flag & AT_SYMLINK_NOFOLLOW) ? NOFOLLOW : FOLLOW; + + if ((error = getutimens(tptr, tptrseg, ts)) != 0) + return (error); + NDINIT_ATRIGHTS(&nd, LOOKUP, follow | MPSAFE | AUDITVNODE1, pathseg, + path, fd, CAP_FUTIMES, td); + + if ((error = namei(&nd)) != 0) + return (error); + vfslocked = NDHASGIANT(&nd); + NDFREE(&nd, NDF_ONLY_PNBUF); + error = setutimes(td, nd.ni_vp, ts, 2, tptr == NULL); + vrele(nd.ni_vp); + VFS_UNLOCK_GIANT(vfslocked); + return (error); +} + +/* * Truncate a file given its path name. */ #ifndef _SYS_SYSPROTO_H_ diff --git a/sys/security/audit/audit_bsm.c b/sys/security/audit/audit_bsm.c index a8fcd8f..22157d8 100644 --- a/sys/security/audit/audit_bsm.c +++ b/sys/security/audit/audit_bsm.c @@ -756,6 +756,7 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) case AUE_UNLINK: case AUE_UNLINKAT: case AUE_UTIMES: + case AUE_UTIMENSAT: ATFD1_TOKENS(1); UPATH1_VNODE1_TOKENS; break; @@ -934,6 +935,7 @@ kaudit_to_bsm(struct kaudit_record *kar, struct au_record **pau) case AUE_FSYNC: case AUE_FTRUNCATE: case AUE_FUTIMES: + case AUE_FUTIMENS: case AUE_GETDIRENTRIES: case AUE_GETDIRENTRIESATTR: case AUE_LSEEK: diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 1b03bd2..099a1b4 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -289,6 +289,11 @@ struct nstat { #endif /* __BSD_VISIBLE */ +#if __BSD_VISIBLE || __POSIX_VISIBLE >= 200809 +#define UTIME_NOW -2L +#define UTIME_OMIT -1L +#endif + #ifndef _KERNEL __BEGIN_DECLS #if __BSD_VISIBLE @@ -324,6 +329,8 @@ mode_t umask(mode_t); int fstatat(int, const char *, struct stat *, int); int mkdirat(int, const char *, mode_t); int mkfifoat(int, const char *, mode_t); +int futimens(int, const struct timespec [2]); +int utimensat(int, const char *, const struct timespec [2], int); #endif #if __BSD_VISIBLE || __XSI_VISIBLE >= 700 int mknodat(int, const char *, mode_t, dev_t); diff --git a/sys/sys/syscall.h b/sys/sys/syscall.h index a9a1fb2..305ac78 100644 --- a/sys/sys/syscall.h +++ b/sys/sys/syscall.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ #define SYS_syscall 0 @@ -450,4 +450,6 @@ #define SYS_rctl_remove_rule 529 #define SYS_posix_fallocate 530 #define SYS_posix_fadvise 531 -#define SYS_MAXSYSCALL 532 +#define SYS_utimensat 532 +#define SYS_futimens 533 +#define SYS_MAXSYSCALL 534 diff --git a/sys/sys/syscall.mk b/sys/sys/syscall.mk index 1113886..f42eba2 100644 --- a/sys/sys/syscall.mk +++ b/sys/sys/syscall.mk @@ -1,7 +1,7 @@ # FreeBSD system call names. # DO NOT EDIT-- this file is automatically generated. # $FreeBSD$ -# created from FreeBSD: head/sys/kern/syscalls.master 227691 2011-11-19 06:35:15Z ed +# created from FreeBSD MIASM = \ syscall.o \ exit.o \ @@ -398,4 +398,6 @@ MIASM = \ rctl_add_rule.o \ rctl_remove_rule.o \ posix_fallocate.o \ - posix_fadvise.o + posix_fadvise.o \ + utimensat.o \ + futimens.o diff --git a/sys/sys/syscallsubr.h b/sys/sys/syscallsubr.h index 08dba2f..6b42797 100644 --- a/sys/sys/syscallsubr.h +++ b/sys/sys/syscallsubr.h @@ -93,6 +93,8 @@ int kern_fhstatfs(struct thread *td, fhandle_t fh, struct statfs *buf); int kern_fstat(struct thread *td, int fd, struct stat *sbp); int kern_fstatfs(struct thread *td, int fd, struct statfs *buf); int kern_ftruncate(struct thread *td, int fd, off_t length); +int kern_futimens(struct thread *, int, const struct timespec *, + enum uio_seg); int kern_futimes(struct thread *td, int fd, struct timeval *tptr, enum uio_seg tptrseg); int kern_getdirentries(struct thread *td, int fd, char *buf, u_int count, @@ -227,6 +229,8 @@ int kern_truncate(struct thread *td, char *path, enum uio_seg pathseg, int kern_unlink(struct thread *td, char *path, enum uio_seg pathseg); int kern_unlinkat(struct thread *td, int fd, char *path, enum uio_seg pathseg, ino_t oldinum); +int kern_utimensat(struct thread *, int, const char *, enum uio_seg, + const struct timespec *, enum uio_seg, int); int kern_utimes(struct thread *td, char *path, enum uio_seg pathseg, struct timeval *tptr, enum uio_seg tptrseg); int kern_utimesat(struct thread *td, int fd, char *path, diff --git a/sys/sys/sysproto.h b/sys/sys/sysproto.h index 84a0ed7..25c4366 100644 --- a/sys/sys/sysproto.h +++ b/sys/sys/sysproto.h @@ -3,7 +3,7 @@ * * DO NOT EDIT-- this file is automatically generated. * $FreeBSD$ - * created from FreeBSD: head/sys/kern/syscalls.master 227691 2011-11-19 06:35:15Z ed + * created from FreeBSD */ #ifndef _SYS_SYSPROTO_H_ @@ -1749,6 +1749,16 @@ struct posix_fadvise_args { char len_l_[PADL_(off_t)]; off_t len; char len_r_[PADR_(off_t)]; char advice_l_[PADL_(int)]; int advice; char advice_r_[PADR_(int)]; }; +struct utimensat_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char path_l_[PADL_(const char *)]; const char * path; char path_r_[PADR_(const char *)]; + char times_l_[PADL_(const struct timespec *)]; const struct timespec * times; char times_r_[PADR_(const struct timespec *)]; + char flag_l_[PADL_(int)]; int flag; char flag_r_[PADR_(int)]; +}; +struct futimens_args { + char fd_l_[PADL_(int)]; int fd; char fd_r_[PADR_(int)]; + char times_l_[PADL_(const struct timespec *)]; const struct timespec * times; char times_r_[PADR_(const struct timespec *)]; +}; int nosys(struct thread *, struct nosys_args *); void sys_sys_exit(struct thread *, struct sys_exit_args *); int sys_fork(struct thread *, struct fork_args *); @@ -2129,6 +2139,8 @@ int sys_rctl_add_rule(struct thread *, struct rctl_add_rule_args *); int sys_rctl_remove_rule(struct thread *, struct rctl_remove_rule_args *); int sys_posix_fallocate(struct thread *, struct posix_fallocate_args *); int sys_posix_fadvise(struct thread *, struct posix_fadvise_args *); +int sys_utimensat(struct thread *, struct utimensat_args *); +int sys_futimens(struct thread *, struct futimens_args *); #ifdef COMPAT_43 @@ -2823,6 +2835,8 @@ int freebsd7_shmctl(struct thread *, struct freebsd7_shmctl_args *); #define SYS_AUE_rctl_remove_rule AUE_NULL #define SYS_AUE_posix_fallocate AUE_NULL #define SYS_AUE_posix_fadvise AUE_NULL +#define SYS_AUE_utimensat AUE_UTIMENSAT +#define SYS_AUE_futimens AUE_FUTIMENS #undef PAD_ #undef PADL_