diff options
author | Flávio Cruz <flaviocruz@gmail.com> | 2018-03-05 02:58:41 +0100 |
---|---|---|
committer | Samuel Thibault <samuel.thibault@ens-lyon.org> | 2018-03-05 02:58:41 +0100 |
commit | 82ab5bbac5d115b7cae4f3ca28f3ba8cce9431ba (patch) | |
tree | 2170bfb251afe6f2173c4424efa18e0b3fc0b46f | |
parent | 2ed669b5b1da77e80fff6dc2f72f11e266479a8c (diff) | |
download | hurd-82ab5bbac5d115b7cae4f3ca28f3ba8cce9431ba.tar.gz hurd-82ab5bbac5d115b7cae4f3ca28f3ba8cce9431ba.tar.bz2 hurd-82ab5bbac5d115b7cae4f3ca28f3ba8cce9431ba.zip |
Add file_utimens RPC to use a struct timespec
and update the servers to use UTIME_NOW and UTIME_OMIT.
* console-client/trans.c (netfs_attempt_utimes): Do not set current time
ourself.
* console/console.c (netfs_attempt_utimes): Likewise.
* ftpfs/netfs.c (netfs_attempt_utimes): Likewise.
* hostmux/node.c (netfs_attempt_utimes): Likewise.
* usermux/node.c (netfs_attempt_utimes): Likewise.
* nfs/ops.c (netfs_attempt_utimes): Likewise.
* doc/hurd.texi (file_utimens): Add documentation.
* hurd/fs.defs (file_utimens): Add RPC.
* libdiskfs/file-utimes.c (diskfs_S_file_utimes): Move implementation
and replace with translation layer with...
(diskfs_S_file_utimens): ... new function.
* libnetfs/file-utimes.c (netfs_S_file_utimes): Likewise with...
(netfs_S_file_utimens): ... new function.
* libnetfs/init-init.c: Include <error.h>.
(netfs_mtime): New variable.
(netfs_init): New function.
* libnetfs/netfs.h (netfs_attempt_utimes): Update documentation.
* libnetfs/priv.h (netfs_mtime): Declare variable.
* libtreefs/s-file.c (treefs_S_file_utimes): Convert time values and
call treefs_s_file_utimens instead of treefs_s_file_utimes.
* libtreefs/treefs-hooks.h: Replace TREEFS_HOOK_S_FILE_UTIMES with
TREEFS_HOOK_S_FILE_UTIMENS.
* libtreefs/treefs-s-hooks.h: Replace s_file_utimes with s_file_utimens.
* libtrivfs/file-utimes.c (trivfs_S_file_utimens): New function.
* libtrivfs/times.c (trivfs_set_atime): Try to use file_utimens before
using file_utimes.
(trivfs_set_mtime): Likewise.
* nfsd/ops.c (complete_setattr): Likewise.
* trans/fakeroot.c (netfs_attempt_utimes): Likewise.
* nfs/nfs.c (xdr_encode_sattr_times): Do not set atime or mtime when
they are NULL.
* configure.ac: Look for file_futimens, and define UTIME_NOW/OMIT, for
compatibility with old glibcs.
-rw-r--r-- | configure.ac | 5 | ||||
-rw-r--r-- | console-client/trans.c | 8 | ||||
-rw-r--r-- | console/console.c | 8 | ||||
-rw-r--r-- | doc/hurd.texi | 8 | ||||
-rw-r--r-- | ftpfs/netfs.c | 8 | ||||
-rw-r--r-- | hostmux/node.c | 12 | ||||
-rw-r--r-- | hurd/fs.defs | 10 | ||||
-rw-r--r-- | libdiskfs/file-utimes.c | 41 | ||||
-rw-r--r-- | libnetfs/file-utimes.c | 52 | ||||
-rw-r--r-- | libnetfs/init-init.c | 7 | ||||
-rw-r--r-- | libnetfs/netfs.h | 2 | ||||
-rw-r--r-- | libnetfs/priv.h | 2 | ||||
-rw-r--r-- | libtreefs/s-file.c | 30 | ||||
-rw-r--r-- | libtreefs/treefs-hooks.h | 2 | ||||
-rw-r--r-- | libtreefs/treefs-s-hooks.h | 6 | ||||
-rw-r--r-- | libtrivfs/file-utimes.c | 34 | ||||
-rw-r--r-- | libtrivfs/times.c | 64 | ||||
-rw-r--r-- | nfs/nfs.c | 46 | ||||
-rw-r--r-- | nfs/ops.c | 15 | ||||
-rw-r--r-- | nfsd/ops.c | 62 | ||||
-rw-r--r-- | trans/fakeroot.c | 47 | ||||
-rw-r--r-- | usermux/node.c | 8 |
22 files changed, 341 insertions, 136 deletions
diff --git a/configure.ac b/configure.ac index 89107a97..e8bdc46a 100644 --- a/configure.ac +++ b/configure.ac @@ -165,6 +165,11 @@ AC_SUBST(VERSIONING) # Check if libc contains these functions. AC_CHECK_FUNCS(file_exec_paths exec_exec_paths _hurd_exec_paths) +# Compatibility with glibc < 2.28 +AC_CHECK_FUNCS(file_futimens) +AC_DEFINE([UTIME_NOW],[-1]) +AC_DEFINE([UTIME_OMIT],[-2]) + # From glibc HEAD, 2007-11-07. AC_CACHE_CHECK(for -fgnu89-inline, libc_cv_gnu89_inline, [dnl diff --git a/console-client/trans.c b/console-client/trans.c index 4b9c92b9..69026b16 100644 --- a/console-client/trans.c +++ b/console-client/trans.c @@ -186,14 +186,10 @@ netfs_attempt_utimes (struct iouser *cred, struct node *np, if (! err) { if (mtime) - np->nn_stat.st_mtim = *mtime; - else - flags |= TOUCH_MTIME; + np->nn_stat.st_mtim = *mtime; if (atime) - np->nn_stat.st_atim = *atime; - else - flags |= TOUCH_ATIME; + np->nn_stat.st_atim = *atime; fshelp_touch (&np->nn_stat, flags, console_maptime); } diff --git a/console/console.c b/console/console.c index 94de0049..6e83fbbc 100644 --- a/console/console.c +++ b/console/console.c @@ -510,14 +510,10 @@ netfs_attempt_utimes (struct iouser *cred, struct node *node, if (! err) { if (mtime) - node->nn_stat.st_mtim = *mtime; - else - flags |= TOUCH_MTIME; + node->nn_stat.st_mtim = *mtime; if (atime) - node->nn_stat.st_atim = *atime; - else - flags |= TOUCH_ATIME; + node->nn_stat.st_atim = *atime; fshelp_touch (&node->nn_stat, flags, console_maptime); } diff --git a/doc/hurd.texi b/doc/hurd.texi index e77894a3..7ad798a9 100644 --- a/doc/hurd.texi +++ b/doc/hurd.texi @@ -2722,6 +2722,14 @@ the file. Making this call must cause the @var{ctime} to be updated as well, even if no actual change to either the @var{mtime} or the @var{atime} occurs. +@findex file_utimens +The @code{file_utimens} RPC changes the @var{atime} and @var{mtime} of +the file with nanosecond precision. Making this call must cause the +@var{ctime} to be updated as well, even if no actual change to either the +@var{mtime} or the @var{atime} occurs. The arguments @var{atime} and +@var{mtime} follow the POSIX standard and may use the flags +@code{UTIME_OMIT} and @code{UTIME_NOW}. + @findex file_set_size The @code{file_set_size} RPC is special; not only does it change the status word specifying the size of the file, but it also changes the diff --git a/ftpfs/netfs.c b/ftpfs/netfs.c index cf5d9079..b0c80db1 100644 --- a/ftpfs/netfs.c +++ b/ftpfs/netfs.c @@ -77,14 +77,10 @@ netfs_attempt_utimes (struct iouser *cred, struct node *node, if (! err) { if (atime) - node->nn_stat.st_atim = *atime; - else - flags |= TOUCH_ATIME; + node->nn_stat.st_atim = *atime; if (mtime) - node->nn_stat.st_mtim = *mtime; - else - flags |= TOUCH_MTIME; + node->nn_stat.st_mtim = *mtime; fshelp_touch (&node->nn_stat, flags, ftpfs_maptime); } diff --git a/hostmux/node.c b/hostmux/node.c index 7167300f..f1e17769 100644 --- a/hostmux/node.c +++ b/hostmux/node.c @@ -78,16 +78,12 @@ netfs_attempt_utimes (struct iouser *cred, struct node *node, if (! err) { - if (mtime) - node->nn_stat.st_mtim = *mtime; - else - flags |= TOUCH_MTIME; - if (atime) - node->nn_stat.st_atim = *atime; - else - flags |= TOUCH_ATIME; + node->nn_stat.st_atim = *atime; + if (mtime) + node->nn_stat.st_mtim = *mtime; + fshelp_touch (&node->nn_stat, flags, hostmux_maptime); } return err; diff --git a/hurd/fs.defs b/hurd/fs.defs index 14800d9a..1460131a 100644 --- a/hurd/fs.defs +++ b/hurd/fs.defs @@ -376,3 +376,13 @@ routine file_exec_paths ( intarray: intarray_t SCP; deallocnames: mach_port_name_array_t SCP; destroynames: mach_port_name_array_t SCP); + +/* Change access and modify times with nanosecond precision */ +/* If the nanoseconds value is UTIME_NOW then the time should be + set to the current time and the remainder of the time_value_t ignored. + If the nanoseconds value is UTIME_OMIT then the time is ignored. */ +routine file_utimens ( + utimes_file: file_t; + RPT + new_atime: timespec_t; + new_mtime: timespec_t); diff --git a/libdiskfs/file-utimes.c b/libdiskfs/file-utimes.c index 29839fc9..13751d0b 100644 --- a/libdiskfs/file-utimes.c +++ b/libdiskfs/file-utimes.c @@ -24,6 +24,33 @@ diskfs_S_file_utimes (struct protid *cred, time_value_t atime, time_value_t mtime) { + struct timespec atim, mtim; + + if (atime.microseconds == -1) + { + atim.tv_sec = 0; + atim.tv_nsec = UTIME_NOW; + } + else + TIME_VALUE_TO_TIMESPEC (&atime, &atim); + + if (mtime.microseconds == -1) + { + mtim.tv_sec = 0; + mtim.tv_nsec = UTIME_NOW; + } + else + TIME_VALUE_TO_TIMESPEC (&mtime, &mtim); + + return diskfs_S_file_utimens (cred, atim, mtim); +} + +/* Implement file_utimens as described in <hurd/fs.defs>. */ +kern_return_t +diskfs_S_file_utimens (struct protid *cred, + struct timespec atime, + struct timespec mtime) +{ CHANGE_NODE_FIELD (cred, ({ if (!(err = fshelp_isowner (&np->dn_stat, cred->user))) @@ -31,21 +58,23 @@ diskfs_S_file_utimes (struct protid *cred, /* Flush pending updates first. */ diskfs_set_node_times (np); - if (atime.microseconds == -1) + if (atime.tv_nsec == UTIME_NOW) np->dn_set_atime = 1; + else if (atime.tv_nsec == UTIME_OMIT) + ; /* do nothing */ else { - np->dn_stat.st_atim.tv_sec = atime.seconds; - np->dn_stat.st_atim.tv_nsec = atime.microseconds * 1000; + np->dn_stat.st_atim = atime; np->dn_set_atime = 0; } - if (mtime.microseconds == -1) + if (mtime.tv_nsec == UTIME_NOW) np->dn_set_mtime = 1; + else if (mtime.tv_nsec == UTIME_OMIT) + ; /* do nothing */ else { - np->dn_stat.st_mtim.tv_sec = mtime.seconds; - np->dn_stat.st_mtim.tv_nsec = mtime.microseconds * 1000; + np->dn_stat.st_mtim = mtime; np->dn_set_mtime = 0; } diff --git a/libnetfs/file-utimes.c b/libnetfs/file-utimes.c index 19156094..042c43e8 100644 --- a/libnetfs/file-utimes.c +++ b/libnetfs/file-utimes.c @@ -26,28 +26,52 @@ netfs_S_file_utimes (struct protid *user, time_value_t atimein, time_value_t mtimein) { - struct timespec atime, mtime; - error_t err; + struct timespec atim, mtim; - if (atimein.microseconds != -1) + if (atimein.microseconds == -1) { - atime.tv_sec = atimein.seconds; - atime.tv_nsec = atimein.microseconds * 1000; + atim.tv_sec = 0; + atim.tv_nsec = UTIME_NOW; } - - if (mtimein.microseconds != -1) + else + TIME_VALUE_TO_TIMESPEC (&atimein, &atim); + + if (mtimein.microseconds == -1) { - mtime.tv_sec = mtimein.seconds; - mtime.tv_nsec = mtimein.microseconds * 1000; + mtim.tv_sec = 0; + mtim.tv_nsec = UTIME_NOW; } - + else + TIME_VALUE_TO_TIMESPEC (&mtimein, &mtim); + + return netfs_S_file_utimens (user, atim, mtim); +} + +error_t +netfs_S_file_utimens (struct protid *user, + struct timespec atimein, + struct timespec mtimein) +{ + error_t err; + struct timeval t; + if (!user) return EOPNOTSUPP; - + + if (atimein.tv_nsec == UTIME_NOW || mtimein.tv_nsec == UTIME_NOW) + { + maptime_read (netfs_mtime, &t); + + if (atimein.tv_nsec == UTIME_NOW) + TIMEVAL_TO_TIMESPEC (&t, &atimein); + if (mtimein.tv_nsec == UTIME_NOW) + TIMEVAL_TO_TIMESPEC (&t, &mtimein); + } + pthread_mutex_lock (&user->po->np->lock); - err = netfs_attempt_utimes (user->user, user->po->np, - atimein.microseconds != -1 ? &atime : 0, - mtimein.microseconds != -1 ? &mtime : 0); + err = netfs_attempt_utimes (user->user, user->po->np, + (atimein.tv_nsec == UTIME_OMIT) ? 0 : &atimein, + (mtimein.tv_nsec == UTIME_OMIT) ? 0 : &mtimein); pthread_mutex_unlock (&user->po->np->lock); return err; } diff --git a/libnetfs/init-init.c b/libnetfs/init-init.c index 9ca1aacf..984a5e71 100644 --- a/libnetfs/init-init.c +++ b/libnetfs/init-init.c @@ -20,6 +20,7 @@ #include "netfs.h" +#include <error.h> /* For safe inlining of netfs_node_netnode and netfs_netnode_node. */ size_t const _netfs_sizeof_struct_node = sizeof (struct node); @@ -30,11 +31,17 @@ struct port_class *netfs_protid_class = 0; struct port_class *netfs_control_class = 0; auth_t netfs_auth_server_port = 0; mach_port_t netfs_fsys_identity; +volatile struct mapped_time_value *netfs_mtime; void netfs_init () { + error_t err; + err = maptime_map (0, 0, &netfs_mtime); + if (err) + error (2, err, "mapping time"); + netfs_protid_class = ports_create_class (netfs_release_protid, 0); netfs_control_class = ports_create_class (0, 0); netfs_port_bucket = ports_create_bucket (); diff --git a/libnetfs/netfs.h b/libnetfs/netfs.h index 5b5ca93b..3d51b74b 100644 --- a/libnetfs/netfs.h +++ b/libnetfs/netfs.h @@ -173,7 +173,7 @@ error_t netfs_attempt_chflags (struct iouser *cred, struct node *np, /* The user must define this function. This should attempt a utimes call for the user specified by CRED on locked node NP, to change the atime to ATIME and the mtime to MTIME. If ATIME or MTIME is - null, then set to the current time. */ + null, then do not change it. */ error_t netfs_attempt_utimes (struct iouser *cred, struct node *np, struct timespec *atime, struct timespec *mtime); diff --git a/libnetfs/priv.h b/libnetfs/priv.h index 3c5bcd4f..3871da8d 100644 --- a/libnetfs/priv.h +++ b/libnetfs/priv.h @@ -25,6 +25,8 @@ #include "netfs.h" +volatile struct mapped_time_value *netfs_mtime; + static inline struct protid * __attribute__ ((unused)) begin_using_protid_port (file_t port) { diff --git a/libtreefs/s-file.c b/libtreefs/s-file.c index c24d645e..6ba67e3c 100644 --- a/libtreefs/s-file.c +++ b/libtreefs/s-file.c @@ -231,5 +231,33 @@ treefs_S_file_utimes (struct treefs_protid *cred, { if (!cred) return EOPNOTSUPP; - return treefs_s_file_utimes (cred, atime, mtime); + + struct timespec atim, mtim; + + if (atime.microseconds == -1) + { + atim.tv_sec = 0; + atim.tv_nsec = UTIME_NOW; + } + else + TIME_VALUE_TO_TIMESPEC (&atime, &atim); + + if (mtime.microseconds == -1) + { + mtim.tv_sec = 0; + mtim.tv_nsec = UTIME_NOW; + } + else + TIME_VALUE_TO_TIMESPEC (&mtime, &mtim); + + return treefs_s_file_utimens (cred, atim, mtim); +} + +error_t +treefs_S_file_utimens (struct treefs_protid *cred, + struct timespec atime, struct timespec mtime) +{ + if (!cred) + return EOPNOTSUPP; + return treefs_s_file_utimens (cred, atime, mtime); } diff --git a/libtreefs/treefs-hooks.h b/libtreefs/treefs-hooks.h index 6dc2f731..49dbb419 100644 --- a/libtreefs/treefs-hooks.h +++ b/libtreefs/treefs-hooks.h @@ -33,7 +33,7 @@ enum /* file rpcs */ TREEFS_HOOK_S_FILE_EXEC, TREEFS_HOOK_S_FILE_CHOWN, TREEFS_HOOK_S_FILE_CHAUTHOR, TREEFS_HOOK_S_FILE_CHMOD, - TREEFS_HOOK_S_FILE_CHFLAGS, TREEFS_HOOK_S_FILE_UTIMES, + TREEFS_HOOK_S_FILE_CHFLAGS, TREEFS_HOOK_S_FILE_UTIMENS, TREEFS_HOOK_S_FILE_SET_SIZE, TREEFS_HOOK_S_FILE_LOCK, TREEFS_HOOK_S_FILE_LOCK_STAT, TREEFS_HOOK_S_FILE_ACCESS, TREEFS_HOOK_S_FILE_NOTICE, TREEFS_HOOK_S_FILE_SYNC, diff --git a/libtreefs/treefs-s-hooks.h b/libtreefs/treefs-s-hooks.h index 2ea9e7ab..9b2489df 100644 --- a/libtreefs/treefs-s-hooks.h +++ b/libtreefs/treefs-s-hooks.h @@ -53,9 +53,9 @@ DHH(s_file_chmod, error_t, mode_t) DHH(s_file_chflags, error_t, int) #define treefs_s_file_chflags(h, args...) \ _TREEFS_CHH(h, S_FILE_CHFLAGS, s_file_chflags , ##args) -DHH(s_file_utimes, error_t, time_value_t, time_value_t) -#define treefs_s_file_utimes(h, args...) \ - _TREEFS_CHH(h, S_FILE_UTIMES, s_file_utimes , ##args) +DHH(s_file_utimens, error_t, struct timespec, struct timespec) +#define treefs_s_file_utimens(h, args...) \ + _TREEFS_CHH(h, S_FILE_UTIMENS, s_file_utimens , ##args) DHH(s_file_truncate, error_t, off_t) #define treefs_s_file_truncate(h, args...) \ _TREEFS_CHH(h, S_FILE_TRUNCATE, s_file_truncate , ##args) diff --git a/libtrivfs/file-utimes.c b/libtrivfs/file-utimes.c index 827c0554..7c5eaf43 100644 --- a/libtrivfs/file-utimes.c +++ b/libtrivfs/file-utimes.c @@ -25,3 +25,37 @@ trivfs_S_file_utimes (struct trivfs_protid *cred, { return cred ? file_utimes (cred->realnode, atime, mtime) : EOPNOTSUPP; } + +kern_return_t +trivfs_S_file_utimens (struct trivfs_protid *cred, + mach_port_t reply, mach_msg_type_name_t reply_type, + struct timespec atime, struct timespec mtime) +{ + kern_return_t err; + + if (!cred) + return EOPNOTSUPP; + +#ifdef HAVE_FILE_UTIMENS + err = file_utimens (cred->realnode, atime, mtime); + + if (err == EMIG_BAD_ID || err == EOPNOTSUPP) +#endif + { + time_value_t atim, mtim; + + if (atime.tv_nsec == UTIME_NOW) + atim.microseconds = -1; + else + TIMESPEC_TO_TIME_VALUE (&atim, &atime); + + if (mtime.tv_nsec == UTIME_NOW) + mtim.microseconds = -1; + else + TIMESPEC_TO_TIME_VALUE (&mtim, &mtime); + + err = file_utimes (cred->realnode, atim, mtim); + } + + return err; +} diff --git a/libtrivfs/times.c b/libtrivfs/times.c index 42e668d7..5e20bf10 100644 --- a/libtrivfs/times.c +++ b/libtrivfs/times.c @@ -21,36 +21,60 @@ error_t trivfs_set_atime (struct trivfs_control *cntl) { error_t err; - struct stat st; - time_value_t atime; - time_value_t mtime; +#ifdef HAVE_FILE_UTIMENS + struct timespec atime; + struct timespec mtime; - err = io_stat (cntl->underlying, &st); - if (err) - return err; + atime.tv_sec = 0; + atime.tv_nsec = UTIME_NOW; + mtime.tv_sec = 0; + mtime.tv_nsec = UTIME_OMIT; - mtime.seconds = st.st_mtim.tv_sec; - mtime.microseconds = st.st_mtim.tv_nsec / 1000; - atime.microseconds = -1; + err = file_utimens (cntl->underlying, atime, mtime); - return file_utimes (cntl->underlying, atime, mtime); + if (err == MIG_BAD_ID || err == EOPNOTSUPP) +#endif + { + struct stat st; + time_value_t atim, mtim; + + io_stat (cntl->underlying, &st); + + TIMESPEC_TO_TIME_VALUE (&atim, &st.st_atim); + mtim.microseconds = -1; + err = file_utimes (cntl->underlying, atim, mtim); + } + + return err; } error_t trivfs_set_mtime (struct trivfs_control *cntl) { error_t err; - struct stat st; - time_value_t atime; - time_value_t mtime; +#ifdef HAVE_FILE_UTIMENS + struct timespec atime; + struct timespec mtime; + + atime.tv_sec = 0; + atime.tv_nsec = UTIME_OMIT; + mtime.tv_sec = 0; + mtime.tv_nsec = UTIME_NOW; + + err = file_utimens (cntl->underlying, atime, mtime); + + if (err == MIG_BAD_ID || err == EOPNOTSUPP) +#endif + { + struct stat st; + time_value_t atim, mtim; - err = io_stat (cntl->underlying, &st); - if (err) - return err; + io_stat (cntl->underlying, &st); - atime.seconds = st.st_atim.tv_sec; - atime.microseconds = st.st_atim.tv_nsec / 1000; - mtime.microseconds = -1; + atim.microseconds = -1; + TIMESPEC_TO_TIME_VALUE (&mtim, &st.st_mtim); + err = file_utimes (cntl->underlying, atim, mtim); + } - return file_utimes (cntl->underlying, atime, mtime); + return err; } @@ -273,10 +273,26 @@ xdr_encode_sattr_times (int *p, struct timespec *atime, struct timespec *mtime) *(p++) = -1; /* uid */ *(p++) = -1; /* gid */ *(p++) = -1; /* size */ - *(p++) = htonl (atime->tv_sec); - *(p++) = htonl (atime->tv_nsec / 1000); - *(p++) = htonl (mtime->tv_sec); - *(p++) = htonl (mtime->tv_nsec / 1000); + if (atime) + { + *(p++) = htonl (atime->tv_sec); + *(p++) = htonl (atime->tv_nsec / 1000); + } + else + { + *(p++) = -1; /* no atime */ + *(p++) = -1; + } + if (mtime) + { + *(p++) = htonl (mtime->tv_sec); + *(p++) = htonl (mtime->tv_nsec / 1000); + } + else + { + *(p++) = -1; /* no mtime */ + *(p++) = -1; + } } else { @@ -284,12 +300,22 @@ xdr_encode_sattr_times (int *p, struct timespec *atime, struct timespec *mtime) *(p++) = 0; /* no uid */ *(p++) = 0; /* no gid */ *(p++) = 0; /* no size */ - *(p++) = htonl (SET_TO_CLIENT_TIME); /* atime */ - *(p++) = htonl (atime->tv_sec); - *(p++) = htonl (atime->tv_nsec); - *(p++) = htonl (SET_TO_CLIENT_TIME); /* mtime */ - *(p++) = htonl (mtime->tv_sec); - *(p++) = htonl (mtime->tv_nsec); + if (atime) + { + *(p++) = htonl (SET_TO_CLIENT_TIME); /* atime */ + *(p++) = htonl (atime->tv_sec); + *(p++) = htonl (atime->tv_nsec); + } + else + *(p++) = DONT_CHANGE; /* no atime */ + if (mtime) + { + *(p++) = htonl (SET_TO_CLIENT_TIME); /* mtime */ + *(p++) = htonl (mtime->tv_sec); + *(p++) = htonl (mtime->tv_nsec); + } + else + *(p++) = DONT_CHANGE; /* no mtime */ } return p; } @@ -297,17 +297,12 @@ netfs_attempt_utimes (struct iouser *cred, struct node *np, int *p; void *rpcbuf; error_t err; - struct timeval tv; - struct timespec current; + + if (!atime && !mtime) + return 0; /* nothing to update */ /* XXX For version 3 we can actually do this right, but we don't just yet. */ - if (!atime || !mtime) - { - maptime_read (mapped_time, &tv); - current.tv_sec = tv.tv_sec; - current.tv_nsec = tv.tv_usec * 1000; - } p = nfs_initialize_rpc (NFSPROC_SETATTR (protocol_version), cred, 0, &rpcbuf, np, -1); @@ -315,9 +310,7 @@ netfs_attempt_utimes (struct iouser *cred, struct node *np, return errno; p = xdr_encode_fhandle (p, &np->nn->handle); - p = xdr_encode_sattr_times (p, - atime ?: ¤t, - mtime ?: ¤t); + p = xdr_encode_sattr_times (p, atime, mtime); if (protocol_version == 3) *(p++) = 0; /* guard check == 0 */ @@ -63,7 +63,7 @@ complete_setattr (mach_port_t port, { uid_t uid, gid; off_t size; - time_value_t atime, mtime; + struct timespec atime, mtime; struct stat st; error_t err; @@ -91,34 +91,48 @@ complete_setattr (mach_port_t port, if (err) return err; - atime.seconds = ntohl (*p); + atime.tv_sec = ntohl (*p); p++; - atime.microseconds = ntohl (*p); + atime.tv_nsec = ntohl (*p) * 1000; p++; - mtime.seconds = ntohl (*p); + mtime.tv_sec = ntohl (*p); p++; - mtime.microseconds = ntohl (*p); + mtime.tv_nsec = ntohl (*p) * 1000; p++; - if (atime.seconds != -1 && atime.microseconds == -1) - atime.microseconds = 0; - if (mtime.seconds != -1 && mtime.microseconds == -1) - mtime.microseconds = 0; - - if (atime.seconds == -1) - atime.seconds = st.st_atim.tv_sec; - if (atime.microseconds == -1) - atime.microseconds = st.st_atim.tv_nsec / 1000; - if (mtime.seconds == -1) - mtime.seconds = st.st_mtim.tv_sec; - if (mtime.microseconds == -1) - mtime.microseconds = st.st_mtim.tv_nsec / 1000; - - if (atime.seconds != st.st_atim.tv_sec - || atime.microseconds != st.st_atim.tv_nsec / 1000 - || mtime.seconds != st.st_mtim.tv_sec - || mtime.microseconds != st.st_mtim.tv_nsec / 1000) - err = file_utimes (port, atime, mtime); + if (atime.tv_sec != -1 && atime.tv_nsec == -1) + atime.tv_nsec = 0; + if (mtime.tv_sec != -1 && mtime.tv_nsec == -1) + mtime.tv_nsec = 0; + + if (atime.tv_nsec == -1) + atime.tv_sec = st.st_atim.tv_sec; + if (atime.tv_nsec == -1) + atime.tv_nsec = st.st_atim.tv_nsec; + if (mtime.tv_sec == -1) + mtime.tv_sec = st.st_mtim.tv_sec; + if (mtime.tv_nsec == -1) + mtime.tv_nsec = st.st_mtim.tv_nsec; + + if (atime.tv_sec != st.st_atim.tv_sec + || atime.tv_nsec != st.st_atim.tv_nsec + || mtime.tv_sec != st.st_mtim.tv_sec + || mtime.tv_nsec != st.st_mtim.tv_nsec) + { +#ifdef HAVE_FILE_UTIMENS + err = file_utimens (port, atime, mtime); + + if (err == MIG_BAD_ID || err == EOPNOTSUPP) +#endif + { + time_value_t atim, mtim; + + TIMESPEC_TO_TIME_VALUE (&atim, &atime); + TIMESPEC_TO_TIME_VALUE (&mtim, &mtime); + + err = file_utimes (port, atim, mtim); + } + } return err; } diff --git a/trans/fakeroot.c b/trans/fakeroot.c index 711a8565..6ef93327 100644 --- a/trans/fakeroot.c +++ b/trans/fakeroot.c @@ -685,26 +685,47 @@ error_t netfs_attempt_utimes (struct iouser *cred, struct node *np, struct timespec *atime, struct timespec *mtime) { - union tv - { - struct timeval tv; - time_value_t tvt; - }; - union tv a, m; + error_t err; +#ifdef HAVE_FILE_UTIMENS + struct timespec tatime, tmtime; + if (atime) + tatime = *atime; + else { - TIMESPEC_TO_TIMEVAL (&a.tv, atime); + tatime.tv_sec = 0; + tatime.tv_nsec = UTIME_OMIT; } - else - a.tv.tv_sec = a.tv.tv_usec = -1; + if (mtime) + tmtime = *mtime; + else { - TIMESPEC_TO_TIMEVAL (&m.tv, mtime); + tmtime.tv_sec = 0; + tmtime.tv_nsec = UTIME_OMIT; } - else - m.tv.tv_sec = m.tv.tv_usec = -1; - return file_utimes (netfs_node_netnode (np)->file, a.tvt, m.tvt); + err = file_utimens (netfs_node_netnode (np)->file, tatime, tmtime); + + if(err == EMIG_BAD_ID || err == EOPNOTSUPP) +#endif + { + time_value_t atim, mtim; + + if(atime) + TIMESPEC_TO_TIME_VALUE (&atim, atime); + else + atim.seconds = atim.microseconds = -1; + + if (mtime) + TIMESPEC_TO_TIME_VALUE (&mtim, mtime); + else + mtim.seconds = mtim.microseconds = -1; + + err = file_utimes (netfs_node_netnode (np)->file, atim, mtim); + } + + return err; } error_t diff --git a/usermux/node.c b/usermux/node.c index 2341714c..66bf79b1 100644 --- a/usermux/node.c +++ b/usermux/node.c @@ -81,14 +81,10 @@ netfs_attempt_utimes (struct iouser *cred, struct node *node, if (! err) { if (mtime) - node->nn_stat.st_mtim = *mtime; - else - flags |= TOUCH_MTIME; + node->nn_stat.st_mtim = *mtime; if (atime) - node->nn_stat.st_atim = *atime; - else - flags |= TOUCH_ATIME; + node->nn_stat.st_atim = *atime; fshelp_touch (&node->nn_stat, flags, usermux_maptime); } |