diff --git a/include/minix/callnr.h b/include/minix/callnr.h index f4417ddf5..e38d881d8 100644 --- a/include/minix/callnr.h +++ b/include/minix/callnr.h @@ -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 */ diff --git a/lib/libc/gen/Makefile.inc b/lib/libc/gen/Makefile.inc index 4ed8a2ec3..142fbb318 100644 --- a/lib/libc/gen/Makefile.inc +++ b/lib/libc/gen/Makefile.inc @@ -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 diff --git a/lib/libc/gen/utimens.c b/lib/libc/gen/utimens.c new file mode 100644 index 000000000..9fb9beeb8 --- /dev/null +++ b/lib/libc/gen/utimens.c @@ -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 +#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 +#include + +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); +} diff --git a/lib/libc/sys-minix/MISSING_SYSCALLS b/lib/libc/sys-minix/MISSING_SYSCALLS index dc75c0669..98ee058c0 100644 --- a/lib/libc/sys-minix/MISSING_SYSCALLS +++ b/lib/libc/sys-minix/MISSING_SYSCALLS @@ -69,9 +69,6 @@ timer_delete timer_gettime timer_settime undelete -utimes -lutimes -futimes utrace uuidgen vadvise diff --git a/lib/libc/sys-minix/Makefile.inc b/lib/libc/sys-minix/Makefile.inc index 542197c7d..98a208fab 100644 --- a/lib/libc/sys-minix/Makefile.inc +++ b/lib/libc/sys-minix/Makefile.inc @@ -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. diff --git a/lib/libc/sys-minix/futimens.c b/lib/libc/sys-minix/futimens.c new file mode 100644 index 000000000..4483260a8 --- /dev/null +++ b/lib/libc/sys-minix/futimens.c @@ -0,0 +1,23 @@ +#include +#include "namespace.h" +#include + +#include + +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)); +} diff --git a/lib/libc/sys-minix/futimes.c b/lib/libc/sys-minix/futimes.c new file mode 100644 index 000000000..7d7d26e0c --- /dev/null +++ b/lib/libc/sys-minix/futimes.c @@ -0,0 +1,31 @@ +#include +#include "namespace.h" +#include + +#include +#include + +#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)); +} diff --git a/lib/libc/sys-minix/lutimes.c b/lib/libc/sys-minix/lutimes.c new file mode 100644 index 000000000..5b6fa5016 --- /dev/null +++ b/lib/libc/sys-minix/lutimes.c @@ -0,0 +1,36 @@ +#include +#include "namespace.h" +#include + +#include +#include +#include +#include +#include + +#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)); +} diff --git a/lib/libc/sys-minix/utimensat.c b/lib/libc/sys-minix/utimensat.c new file mode 100644 index 000000000..26a1aa877 --- /dev/null +++ b/lib/libc/sys-minix/utimensat.c @@ -0,0 +1,43 @@ +#include +#include "namespace.h" +#include + +#include +#include +#include +#include +#include + +/* 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)); +} diff --git a/lib/libc/sys-minix/utimes.c b/lib/libc/sys-minix/utimes.c new file mode 100644 index 000000000..3e8c16f73 --- /dev/null +++ b/lib/libc/sys-minix/utimes.c @@ -0,0 +1,35 @@ +#include +#include "namespace.h" +#include + +#include +#include +#include +#include + +#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)); +} diff --git a/servers/pm/table.c b/servers/pm/table.c index 4a51a8f7c..258ed1501 100644 --- a/servers/pm/table.c +++ b/servers/pm/table.c @@ -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 */ diff --git a/servers/vfs/param.h b/servers/vfs/param.h index 212676621..c31b58fe3 100644 --- a/servers/vfs/param.h +++ b/servers/vfs/param.h @@ -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 diff --git a/servers/vfs/proto.h b/servers/vfs/proto.h index 36c3ef0e8..6e4e40b0e 100644 --- a/servers/vfs/proto.h +++ b/servers/vfs/proto.h @@ -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); diff --git a/servers/vfs/table.c b/servers/vfs/table.c index b65542635..00a0ae05f 100644 --- a/servers/vfs/table.c +++ b/servers/vfs/table.c @@ -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) */ diff --git a/servers/vfs/time.c b/servers/vfs/time.c index 2695dc837..b366dde68 100644 --- a/servers/vfs/time.c +++ b/servers/vfs/time.c @@ -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 #include #include +#include +#include #include "file.h" #include "fproc.h" #include "path.h" @@ -16,10 +19,13 @@ #include #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; +} diff --git a/sys/sys/fcntl.h b/sys/sys/fcntl.h index 15b4a0c21..0fab6a5bc 100644 --- a/sys/sys/fcntl.h +++ b/sys/sys/fcntl.h @@ -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 diff --git a/sys/sys/stat.h b/sys/sys/stat.h index 970d2b5a1..8ca19b735 100644 --- a/sys/sys/stat.h +++ b/sys/sys/stat.h @@ -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 diff --git a/sys/sys/time.h b/sys/sys/time.h index b4f809e40..7bbaf095a 100644 --- a/sys/sys/time.h +++ b/sys/sys/time.h @@ -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 */ diff --git a/usr.sbin/mtree/compare.c b/usr.sbin/mtree/compare.c index 7686f4242..0de6fcdcc 100644 --- a/usr.sbin/mtree/compare.c +++ b/usr.sbin/mtree/compare.c @@ -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