summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFlávio Cruz <flaviocruz@gmail.com>2018-03-05 02:58:41 +0100
committerSamuel Thibault <samuel.thibault@ens-lyon.org>2018-03-05 02:58:41 +0100
commit82ab5bbac5d115b7cae4f3ca28f3ba8cce9431ba (patch)
tree2170bfb251afe6f2173c4424efa18e0b3fc0b46f
parent2ed669b5b1da77e80fff6dc2f72f11e266479a8c (diff)
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.ac5
-rw-r--r--console-client/trans.c8
-rw-r--r--console/console.c8
-rw-r--r--doc/hurd.texi8
-rw-r--r--ftpfs/netfs.c8
-rw-r--r--hostmux/node.c12
-rw-r--r--hurd/fs.defs10
-rw-r--r--libdiskfs/file-utimes.c41
-rw-r--r--libnetfs/file-utimes.c52
-rw-r--r--libnetfs/init-init.c7
-rw-r--r--libnetfs/netfs.h2
-rw-r--r--libnetfs/priv.h2
-rw-r--r--libtreefs/s-file.c30
-rw-r--r--libtreefs/treefs-hooks.h2
-rw-r--r--libtreefs/treefs-s-hooks.h6
-rw-r--r--libtrivfs/file-utimes.c34
-rw-r--r--libtrivfs/times.c64
-rw-r--r--nfs/nfs.c46
-rw-r--r--nfs/ops.c15
-rw-r--r--nfsd/ops.c62
-rw-r--r--trans/fakeroot.c47
-rw-r--r--usermux/node.c8
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;
}
diff --git a/nfs/nfs.c b/nfs/nfs.c
index 77281566..c4d3e157 100644
--- a/nfs/nfs.c
+++ b/nfs/nfs.c
@@ -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;
}
diff --git a/nfs/ops.c b/nfs/ops.c
index e0daae3f..03690b75 100644
--- a/nfs/ops.c
+++ b/nfs/ops.c
@@ -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 ?: &current,
- mtime ?: &current);
+ p = xdr_encode_sattr_times (p, atime, mtime);
if (protocol_version == 3)
*(p++) = 0; /* guard check == 0 */
diff --git a/nfsd/ops.c b/nfsd/ops.c
index aa37c4a4..4be45fb2 100644
--- a/nfsd/ops.c
+++ b/nfsd/ops.c
@@ -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);
}