utimens(2) system call

Variant of utime(2) with struct timespec (with ns precision)
instead of time_t values; also allows for tv_nsec members
the values UTIME_NOW (force update to current time) or
UTIME_OMIT (allow to set either atim or mtim independently.)

Provides a superset of utimes(2), futimes(2), lutimes(2),
and futimens(2).
Provides the same subset of utimensat(2) as does NetBSD 6.
Also import utimens() and lutimeNS() from NetBSD-current.
This commit is contained in:
Antoine Leca 2011-12-24 15:02:54 +01:00 committed by Ben Gras
parent 88414c568c
commit 9131e98a7d
19 changed files with 385 additions and 16 deletions

View file

@ -97,6 +97,7 @@
#define GETPROCNR 104 /* to PM */
#define ISSETUGID 106 /* to PM: ask if process is tainted */
#define GETEPINFO_O 107 /* to PM: get pid/uid/gid of an endpoint */
#define UTIMENS 108 /* to FS: [f]utimens(); also [fl]utimes */
#define SRV_KILL 111 /* to PM: special kill call for RS */
#define GCOV_FLUSH 112 /* flush gcov data from server to gcov files */

View file

@ -1,4 +1,4 @@
# $NetBSD: Makefile.inc,v 1.184 2012/04/12 22:08:32 christos Exp $
# $NetBSD: Makefile.inc,v 1.185 2012/11/03 19:39:21 christos Exp $
# from: @(#)Makefile.inc 8.6 (Berkeley) 5/4/95
# gen sources
@ -48,8 +48,8 @@ SRCS+= _errno.c alarm.c alphasort.c arc4random.c assert.c basename.c clock.c \
sigset.c sigsetops.c sleep.c \
stringlist.c sysconf.c \
syslog.c telldir.c time.c \
times.c toascii.c tolower_.c ttyname.c ttyslot.c \
toupper_.c ualarm.c ulimit.c uname.c unvis.c usleep.c utime.c utmp.c \
times.c toascii.c tolower_.c ttyname.c ttyslot.c toupper_.c ualarm.c \
ulimit.c uname.c unvis.c usleep.c utime.c utimens.c utmp.c \
utmpx.c valloc.c vis.c wait.c waitpid.c warn.c warnx.c \
vwarn.c vwarnx.c verr.c verrx.c wordexp.c
.endif

53
lib/libc/gen/utimens.c Normal file
View file

@ -0,0 +1,53 @@
/* $NetBSD: utimens.c,v 1.1 2012/11/03 19:39:21 christos Exp $ */
/*-
* Copyright (c) 2012 The NetBSD Foundation, Inc.
* All rights reserved.
*
* This code is derived from software contributed to The NetBSD Foundation
* by Christos Zoulas.
*
* 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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>
#if defined(LIBC_SCCS) && !defined(lint)
__RCSID("$NetBSD: utimens.c,v 1.1 2012/11/03 19:39:21 christos Exp $");
#endif /* LIBC_SCCS and not lint */
#include "namespace.h"
#define _INCOMPLETE_XOPEN_C063
#include <fcntl.h>
#include <sys/stat.h>
int
utimens(const char *path, const struct timespec *times)
{
return utimensat(AT_FDCWD, path, times, 0);
}
int
lutimens(const char *path, const struct timespec *times)
{
return utimensat(AT_FDCWD, path, times, AT_SYMLINK_NOFOLLOW);
}

View file

@ -69,9 +69,6 @@ timer_delete
timer_gettime
timer_settime
undelete
utimes
lutimes
futimes
utrace
uuidgen
vadvise

View file

@ -17,6 +17,7 @@ SRCS+= accept.c access.c adjtime.c bind.c brk.c sbrk.c m_closefrom.c getsid.c \
vectorio.c shutdown.c sigaction.c sigpending.c sigreturn.c sigsuspend.c\
sigprocmask.c socket.c socketpair.c stat.c statvfs.c symlink.c \
sync.c syscall.c sysuname.c truncate.c umask.c unlink.c write.c \
utimensat.c utimes.c futimes.c lutimes.c futimens.c \
_exit.c _ucontext.c environ.c __getcwd.c vfork.c sizeup.c init.c
# Minix specific syscalls.

View file

@ -0,0 +1,23 @@
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <sys/stat.h>
int futimens(int fd, const struct timespec tv[2])
{
message m;
static const struct timespec now[2] = { {0, UTIME_NOW}, {0, UTIME_NOW} };
if (tv == NULL) tv = now;
m.m2_i1 = fd;
m.m2_l1 = tv[0].tv_sec;
m.m2_l2 = tv[1].tv_sec;
m.m2_i2 = tv[0].tv_nsec;
m.m2_i3 = tv[1].tv_nsec;
m.m2_p1 = NULL;
m.m2_s1 = 0;
return(_syscall(VFS_PROC_NR, UTIMENS, &m));
}

View file

@ -0,0 +1,31 @@
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <sys/stat.h>
#include <sys/time.h>
#ifdef __weak_alias
__weak_alias(futimes, __futimes50)
#endif
int futimes(int fd, const struct timeval tv[2])
{
message m;
m.m2_i1 = fd;
if (tv == NULL) {
m.m2_l1 = m.m2_l2 = 0;
m.m2_i2 = m.m2_i3 = UTIME_NOW;
}
else {
m.m2_l1 = tv[0].tv_sec;
m.m2_l2 = tv[1].tv_sec;
m.m2_i2 = tv[0].tv_usec * 1000;
m.m2_i3 = tv[1].tv_usec * 1000;
}
m.m2_p1 = NULL;
m.m2_s1 = 0;
return(_syscall(VFS_PROC_NR, UTIMENS, &m));
}

View file

@ -0,0 +1,36 @@
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#ifdef __weak_alias
__weak_alias(lutimes, __lutimes50)
#endif
int lutimes(const char *name, const struct timeval tv[2])
{
message m;
if (name == NULL) return EINVAL;
if (name[0] == '\0') return ENOENT; /* X/Open requirement */
m.m2_i1 = strlen(name) + 1;
m.m2_p1 = (char *) __UNCONST(name);
if (tv == NULL) {
m.m2_l1 = m.m2_l2 = 0;
m.m2_i2 = m.m2_i3 = UTIME_NOW;
}
else {
m.m2_l1 = tv[0].tv_sec;
m.m2_l2 = tv[1].tv_sec;
m.m2_i2 = tv[0].tv_usec * 1000;
m.m2_i3 = tv[1].tv_usec * 1000;
}
m.m2_s1 = AT_SYMLINK_NOFOLLOW;
return(_syscall(VFS_PROC_NR, UTIMENS, &m));
}

View file

@ -0,0 +1,43 @@
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>
#include <limits.h>
#include <errno.h>
/* Implement a very large but not complete subset of the utimensat()
* Posix:2008/XOpen-7 function.
* Are handled the following cases:
* . utimensat(AT_FDCWD, "/some/absolute/path", , )
* . utimensat(AT_FDCWD, "some/path", , )
* . utimensat(fd, "/some/absolute/path", , ) although fd is useless here
* Are not handled the following cases:
* . utimensat(fd, "some/path", , ) path to a file relative to some open fd
*/
int utimensat(int fd, const char *name, const struct timespec tv[2],
int flags)
{
message m;
static const struct timespec now[2] = { {0, UTIME_NOW}, {0, UTIME_NOW} };
if (tv == NULL) tv = now;
if (name == NULL) return EINVAL;
if (name[0] == '\0') return ENOENT; /* POSIX requirement */
if (fd != AT_FDCWD && name[0] != '/') return EINVAL; /* Not supported */
m.m2_i1 = strlen(name) + 1;
m.m2_p1 = (char *) __UNCONST(name);
m.m2_l1 = tv[0].tv_sec;
m.m2_l2 = tv[1].tv_sec;
m.m2_i2 = tv[0].tv_nsec;
m.m2_i3 = tv[1].tv_nsec;
if ((unsigned)flags > SHRT_MAX)
return EINVAL;
else
m.m2_s1 = flags;
return(_syscall(VFS_PROC_NR, UTIMENS, &m));
}

View file

@ -0,0 +1,35 @@
#include <sys/cdefs.h>
#include "namespace.h"
#include <lib.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <string.h>
#include <errno.h>
#ifdef __weak_alias
__weak_alias(utimes, __utimes50)
#endif
int utimes(const char *name, const struct timeval tv[2])
{
message m;
if (name == NULL) return EINVAL;
if (name[0] == '\0') return ENOENT; /* X/Open requirement */
m.m2_i1 = strlen(name) + 1;
m.m2_p1 = (char *) __UNCONST(name);
if (tv == NULL) {
m.m2_l1 = m.m2_l2 = 0;
m.m2_i2 = m.m2_i3 = UTIME_NOW;
}
else {
m.m2_l1 = tv[0].tv_sec;
m.m2_l2 = tv[1].tv_sec;
m.m2_i2 = tv[0].tv_usec * 1000;
m.m2_i3 = tv[1].tv_usec * 1000;
}
m.m2_s1 = 0;
return(_syscall(VFS_PROC_NR, UTIMENS, &m));
}

View file

@ -119,7 +119,7 @@ int (*call_vec[])(void) = {
no_sys, /* 105 = unused */
do_get, /* 106 = issetugid */
do_getepinfo_o, /* 107 = getepinfo XXX: old implementation*/
no_sys, /* 108 = unused */
no_sys, /* 108 = (utimens) */
no_sys, /* 109 = unused */
no_sys, /* 110 = unused */
do_srv_kill, /* 111 = srv_kill */

View file

@ -43,6 +43,10 @@
#define utime_file m2_p1
#define utime_length m2_i1
#define utime_strlen m2_i2
#define utimens_fd m2_i1
#define utimens_ansec m2_i2
#define utimens_mnsec m2_i3
#define utimens_flags m2_s1
#define whence m2_i2
#define svrctl_req m2_i1
#define svrctl_argp m2_p1

View file

@ -280,6 +280,7 @@ int do_lstat(void);
/* time.c */
int do_utime(void);
int do_utimens(void);
/* tll.c */
void tll_downgrade(tll_t *tllp);

View file

@ -123,7 +123,7 @@ int (*call_vec[])(void) = {
no_sys, /* 105 = unused */
no_sys, /* 106 = unused */
no_sys, /* 107 = (getepinfo) */
no_sys, /* 108 = unused */
do_utimens, /* 108 = utimens */
no_sys, /* 109 = unused */
no_sys, /* 110 = unused */
no_sys, /* 111 = (srv_kill) */

View file

@ -2,12 +2,15 @@
*
* The entry points into this file are
* do_utime: perform the UTIME system call
* do_utimens: perform the UTIMENS system call
*/
#include "fs.h"
#include <minix/callnr.h>
#include <minix/com.h>
#include <time.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "file.h"
#include "fproc.h"
#include "path.h"
@ -16,10 +19,13 @@
#include <minix/vfsif.h>
#include "vmnt.h"
#define UTIMENS_STYLE 0 /* utimes(2)/utimensat(2) style, named file */
#define FUTIMENS_STYLE 1 /* futimens(2)/futimes(2) style, file desc. */
/*===========================================================================*
* do_utime *
*===========================================================================*/
int do_utime()
int do_utime(void)
{
/* Perform the utime(name, timep) system call. */
int r;
@ -72,3 +78,136 @@ int do_utime()
put_vnode(vp);
return(r);
}
/*===========================================================================*
* do_utimens *
*===========================================================================*/
int do_utimens(void)
{
/* Perform the utimens(name, times, flag) system call, and its friends.
* Implement a very large but not complete subset of the utimensat()
* Posix:2008/XOpen-7 function.
* Are handled all the following cases:
* . utimensat(AT_FDCWD, "/some/absolute/path", , )
* . utimensat(AT_FDCWD, "some/path", , )
* . utimens("anything", ) really special case of the above two
* . lutimens("anything", ) also really special case of the above
* . utimensat(fd, "/some/absolute/path", , ) although fd is useless here
* . futimens(fd, )
* Are not handled the following cases:
* . utimensat(fd, "some/path", , ) path to a file relative to some open fd
*/
int r, kind, lookup_flags;
struct vnode *vp;
struct filp *filp = NULL; /* initialization required by clueless GCC */
struct vmnt *vmp;
struct timespec actim, modtim, now, newactim, newmodtim;
char fullpath[PATH_MAX];
struct lookup resolve;
vir_bytes vname;
size_t vname_length;
/* The case times==NULL is handled by the caller, replaced with UTIME_NOW */
actim.tv_sec = job_m_in.utime_actime;
actim.tv_nsec = job_m_in.utimens_ansec;
modtim.tv_sec = job_m_in.utime_modtime;
modtim.tv_nsec = job_m_in.utimens_mnsec;
if (job_m_in.utime_file != NULL) {
kind = UTIMENS_STYLE;
if (job_m_in.utimens_flags & ~AT_SYMLINK_NOFOLLOW)
return EINVAL; /* unknown flag */
/* Temporarily open the file */
vname = (vir_bytes) job_m_in.utime_file;
vname_length = (size_t) job_m_in.utime_length;
if (job_m_in.utimens_flags & AT_SYMLINK_NOFOLLOW)
lookup_flags = PATH_RET_SYMLINK;
else
lookup_flags = PATH_NOFLAGS;
lookup_init(&resolve, fullpath, lookup_flags, &vmp, &vp);
resolve.l_vmnt_lock = VMNT_READ;
resolve.l_vnode_lock = VNODE_READ;
/* Temporarily open the file */
if (fetch_name(vname, vname_length, fullpath) != OK) return(err_code);
if ((vp = eat_path(&resolve, fp)) == NULL) return(err_code);
}
else {
kind = FUTIMENS_STYLE;
/* Change timestamps on already-opened fd. Is it valid? */
if (job_m_in.utimens_flags != 0)
return EINVAL; /* unknown flag */
if ((filp = get_filp(job_m_in.utimens_fd, VNODE_READ)) == NULL)
return err_code;
vp = filp->filp_vno;
}
r = OK;
/* Only the owner of a file or the super user can change timestamps. */
if (vp->v_uid != fp->fp_effuid && fp->fp_effuid != SU_UID) r = EPERM;
/* Need write permission (or super user) to 'touch' the file */
if (r != OK && actim.tv_nsec == UTIME_NOW
&& modtim.tv_nsec == UTIME_NOW) r = forbidden(fp, vp, W_BIT);
if (read_only(vp) != OK) r = EROFS; /* Not even su can touch if R/O */
if (r == OK) {
/* Do we need to ask for current time? */
if (actim.tv_nsec == UTIME_NOW
|| actim.tv_nsec == UTIME_OMIT
|| modtim.tv_nsec == UTIME_NOW
|| modtim.tv_nsec == UTIME_OMIT) {
now = clock_timespec();
}
/* Build the request */
switch (actim.tv_nsec) {
case UTIME_NOW:
newactim = now;
break;
case UTIME_OMIT:
newactim.tv_nsec = UTIME_OMIT;
/* Be nice with old FS, put a sensible value in
* otherwise not used field for seconds
*/
newactim.tv_sec = now.tv_sec;
break;
default:
if ( (unsigned)actim.tv_nsec >= 1000000000)
r = EINVAL;
else
newactim = actim;
break;
}
switch (modtim.tv_nsec) {
case UTIME_NOW:
newmodtim = now;
break;
case UTIME_OMIT:
newmodtim.tv_nsec = UTIME_OMIT;
/* Be nice with old FS, put a sensible value */
newmodtim.tv_sec = now.tv_sec;
break;
default:
if ( (unsigned)modtim.tv_nsec >= 1000000000)
r = EINVAL;
else
newmodtim = modtim;
break;
}
}
if (r == OK)
/* Issue request */
r = req_utime(vp->v_fs_e, vp->v_inode_nr, &newactim, &newmodtim);
if (kind == UTIMENS_STYLE) {
/* Close the temporary */
unlock_vnode(vp);
unlock_vmnt(vmp);
put_vnode(vp);
}
else { /* Change timestamps on opened fd. */
unlock_filp(filp);
}
return r;
}

View file

@ -185,14 +185,18 @@ struct flock {
/*
* Constants for X/Open Extended API set 2 (a.k.a. C063)
* linkat(2) - also part of Posix-2008/XPG7
*/
#if defined(_INCOMPLETE_XOPEN_C063) || defined(_KERNEL)
#if (_POSIX_C_SOURCE - 0) >= 200809L || (_XOPEN_SOURCE - 0) >= 700 || \
defined(_NETBSD_SOURCE)
#if defined(_INCOMPLETE_XOPEN_C063) || defined(_KERNEL) || defined(__minix)
#define AT_FDCWD -100 /* Use cwd for relative link target */
#define AT_EACCESS 0x100 /* Use euig/egid for access checks */
#define AT_EACCESS 0x100 /* Use euid/egid for access checks */
#define AT_SYMLINK_NOFOLLOW 0x200 /* Do not follow symlinks */
#define AT_SYMLINK_FOLLOW 0x400 /* Follow symlinks */
#define AT_REMOVEDIR 0x800 /* Remove directory only */
#endif
#endif
#ifndef _KERNEL

View file

@ -295,7 +295,6 @@ int lchflags(const char *, unsigned long);
int lchmod(const char *, mode_t);
#endif /* defined(_NETBSD_SOURCE) && !defined(__minix) */
#ifndef __minix
#ifndef __LIBC12_SOURCE__
/*
* X/Open Extended API set 2 (a.k.a. C063)
@ -315,7 +314,6 @@ int lutimens(const char *, const struct timespec *);
int futimens(int, const struct timespec *);
#endif
#endif
#endif /* !__minix */
__END_DECLS

View file

@ -283,13 +283,14 @@ int gettimeofday(struct timeval * __restrict, void *__restrict);
int setitimer(int, const struct itimerval * __restrict,
struct itimerval * __restrict) __RENAME(__setitimer50);
#endif /* _POSIX_C_SOURCE >= 200112L || _XOPEN_SOURCE || _NETBSD_SOURCE */
#if defined(_XOPEN_SOURCE) || defined(_NETBSD_SOURCE)
int utimes(const char *, const struct timeval [2]) __RENAME(__utimes50);
#endif /* _XOPEN_SOURCE || _NETBSD_SOURCE */
#if defined(_NETBSD_SOURCE) || defined(HAVE_NBTOOL_CONFIG_H)
int adjtime(const struct timeval *, struct timeval *) __RENAME(__adjtime50);
#ifndef __minix
int futimes(int, const struct timeval [2]) __RENAME(__futimes50);
int lutimes(const char *, const struct timeval [2]) __RENAME(__lutimes50);
#endif /* !__minix */
int settimeofday(const struct timeval * __restrict,
const void *__restrict) __RENAME(__settimeofday50);
#endif /* _NETBSD_SOURCE */

View file

@ -142,10 +142,12 @@ lchown(const char *path, uid_t owner, gid_t group)
#endif
static int
utimes(const char *path, const struct timeval times[2])
fake_utimes(const char *path, const struct timeval times[2])
{
return -1;
}
#undef utimes
#define utimes(path, times) fake_utimes(path, times)
#endif
int